Home Tutorials Download Beta Store Forum Documentation KnowledgeBase Wiki Blog

ShiVa3D

Return to Game programming

3D Flocking example - flying objects behaviour  [SOLVED]

All about the StoneScript

3D Flocking example - flying objects behaviour  [SOLVED]

Postby juaxix » 03 Dec 2013, 23:17

This is an example I have coded for a game i'm working on, I'm using @broozar controls to move the char and look around.
The main code of the flocking is this:
Code: Select all
--------------------------------------------------------------------------------
function Enemy_Flocking_AI.fly_onLoop ( )
--------------------------------------------------------------------------------
   local s      = application.getCurrentUserScene ( )
   local hPlayer= this.player ( )
   local hEnemy = this.getObject ( )
   -- new code here
    local osa = object.setAIVariable
    local oga = object.getAIVariable
    local gga = group.getSubObjectAt
    local mi  = math.min
    local ma  = math.max
    local mvn = math.vectorNormalize
    local mvl = math.vectorLength
    local n   = group.getSubObjectCount ( hEnemy ) - 1
    local ogt = object.getDistanceToObject
    local sghc= scene.getFirstHitColliderWithIDEx
    local ogd = object.getDirection
    local ogtr= object.getTranslation
    local ola = object.lookAt
    local ostr= object.setTranslation
    local ot  = object.translate
    local ott = object.translateTo
    local mxs = this.maxspeed ( )
    local mxf = this.maxforce ( )
    local dt  = application.getLastFrameTime ( )
    local px,py,pz = object.getTranslation ( this.player ( ),object.kGlobalSpace ) -- seek force
    local space    = object.kGlobalSpace
    local radius   = this.r ( )
    -- iterate each enemy and update the position
    for i=0,n do
        -------------------------------------------------
        --- GET CHILD
        -------------------------------------------------
        local child = gga ( hEnemy, i )
        -------------------------------------------------
        if child then
            -- check for the player position
            local cx,cy,cz = ogtr ( child, space  )
            local distance = ogt  ( child, hPlayer)
            if distance > 1 then
                local vx,vy,vz = 0,0,0 -- child velocity force
                local desiredx,desiredy,desiredz = px-cx,py+0.2-cy,pz-cz -- A vector pointing from the location to the target
                local d = mvl (desiredx,desiredy,desiredz)
                -- Scale with arbitrary damping within 10 meters
                if d < 19 then
                  desiredx,desiredy,desiredz = math.vectorSetLength ( desiredx,desiredy,desiredz,this.map(d,0,10,0,mxs) )
                else
                  desiredx,desiredy,desiredz = math.vectorSetLength ( desiredx,desiredy,desiredz,mxs )
                end
                ----------------------------------------
                ---  Steering = Desired minus Velocity
                ----------------------------------------
                local steerx,steery,steerz =  desiredx - oga(child,"SubEnemy_AI","vx"),desiredy - oga(child,"SubEnemy_AI","vy"),desiredz - oga(child,"SubEnemy_AI","vz")
                -- Limit to maximum steering force
                steerx,steery,steerz = mi(steerx,mxf),mi(steery,mxf),mi(steerz ,mxf)
                vx,vy,vz = vx+steerx,vy+steery,vz+steerz
               
                ----------------------------------------
                ---  Separation = Method checks for nearby enemies and steers away
                ----------------------------------------
                local desiredseparation = radius
                local sepx,sepy,sepz    = 0,0,0
                local count = 0
                -- For every enemy in the table, check if it's too close
                for j=0,n do
                    -- only check for other enemies
                    if i~=j then
                        local e  = gga( hEnemy,j )
                        if e then
                          local de = ogt(child, e)
                          if de < desiredseparation then
                            -- Calculate vector pointing away from neighbor
                            local ex,ey,ez = ogtr ( e, space )
                            local diffx,diffy,diffz = mvn( cx-ex,cy-ey,cz-ez )
                            sepx,sepy,sepz = sepx+diffx/de,sepy+diffy/de,sepz+diffz/de
                            count = count + 1 -- Keep track of how many
                          end
                        end
                    end
                end
                -- Average -- divide by how many
                if count > 0 then
                  sepx,sepy,sepz = mvn(sepx / count,sepy / count,sepz / count)
                  -- Our desired vector is the average scaled to maximum speed
                  sepx,sepy,sepz = mi(mxf,sepx*mxs - vx ),mi(mxf,sepy*mxs - vy) ,mi(mxf,sepz*mxs - vz)
                  -- Implement Reynolds: Steering = Desired - Velocity
                  vx,vy,vz = vx+sepx,vy+sepy,vz+sepz
                end
               
                ----------------------------------------
                -- Avoid Walls               
                ----------------------------------------
                local avoidx,avoidy,avoidz = 0,0,0
                local dx,dy,dz = ogd ( child, space )
                local hGround,dw,wx,wy,wz,wi,wj,wk = sghc ( s,cx,cy,cz,dx,dy,dz,radius*2,0 ) -- get the first wall in my direction in a distance limit
                if hGround then
                    avoidx,avoidy,avoidz = mvn ( vx-wx, vy-wy, vz-wz )
                    -- apply force now
                    vx,vy,vz = mi(avoidx,mxs),mi(avoidy,mxs),mi(avoidz,mxs)
                end
               
                ----------------------------------------
   
                -- Limit to maximum speed force before apply it to the child
                vx,vy,vz = mi(vx,mxs),mi(vy,mxs),mi(vz,mxs)
               
                -- translate child with velocity force
                ott ( child,cx+vx,cy+vy,cz+vz,space,dt*10 )
               
               
                -- Avoid Ground
                cx,cy,cz = ogtr ( child , space )
                hGround,dw,wx,wy,wz,wi,wj,wk = sghc ( s,cx,cy+3,cz,0,-1,0,4+radius*2,0 ) -- from the center of the object to the ground
                if hGround then
                    ostr ( child, cx,ma(cy,wy+radius),cz,space )
                end
               
                -- set look at
                ola ( child, px,py,pz,space, dt*4 )
            else
                ----------------------------------------
                -- Attack behaviours
                ----------------------------------------
               
               
               
            end
        -------------------------------------------------
        end
    end
   
--------------------------------------------------------------------------------
end
--------------------------------------------------------------------------------



Video of this example running:
http://www.youtube.com/watch?v=PAsWlvuAupU
It would be unbelievable if you guys add here your own behaviours, like chasing player in the ground (like spiders) or another type of pattern.

Download example.

You can change the movement speed and the amount of force applied for each force, change the final vx,vy,vz multiplying it with a number to give the importance to separation, avoid walls or follow the player...

It can fail for behaviours where object must not fly as it uses Y space to fly, and if the level geometry is complicated between the roof and the floor.
User avatar
juaxix
Platinum Boarder
Platinum Boarder
 
Posts: 328
Location: Spain

Re: 3D Flocking example - flying objects behaviour

Postby Badger » 04 Dec 2013, 02:21

Thanks for the sample :)
________________________________
˙ןǝnuɐɯɯǝ osןɐ ɯ,ı
User avatar
Badger
Gold Boarder
Gold Boarder
 
Posts: 181
Location: Australia

Re: 3D Flocking example - flying objects behaviour

Postby flim » 04 Dec 2013, 05:13

Thanks for sharing :D
flim
Gold Boarder
Gold Boarder
 
Posts: 205

Re: 3D Flocking example - flying objects behaviour

Postby Fraser » 04 Dec 2013, 05:33

Great stuff, i like it. Emergent behaviour is very attractive to an indie dev.

Seperation and wall avoidance could maybe hacked with oversized sphere physics, the visible model tracking it with a soft translateTo, may reduce CPU load. but then may not work as well, perhaps worth the experiment though?
Fraser Ashworth,
https://www.cortex7.net
User avatar
Fraser
Platinum Boarder
Platinum Boarder
 
Posts: 1086
Location: Europe

Re: 3D Flocking example - flying objects behaviour

Postby juaxix » 04 Dec 2013, 09:47

Fraser wrote:Great stuff, i like it. Emergent behaviour is very attractive to an indie dev.

Seperation and wall avoidance could maybe hacked with oversized sphere physics, the visible model tracking it with a soft translateTo, may reduce CPU load. but then may not work as well, perhaps worth the experiment though?

provide example and we do the benchmarks ;)
User avatar
juaxix
Platinum Boarder
Platinum Boarder
 
Posts: 328
Location: Spain

Re: 3D Flocking example - flying objects behaviour

Postby freezer » 04 Dec 2013, 17:18

Bit busy at mo but i'll try and have a look at the weekend... here's a play thing I did a while back...
http://avidfish.com/play/nums.html
freezer
Gold Boarder
Gold Boarder
 
Posts: 216

Re: 3D Flocking example - flying objects behaviour

Postby juaxix » 04 Dec 2013, 17:50

freezer wrote:Bit busy at mo but i'll try and have a look at the weekend... here's a play thing I did a while back...
http://avidfish.com/play/nums.html

nice, do you share the code? :roll:
User avatar
juaxix
Platinum Boarder
Platinum Boarder
 
Posts: 328
Location: Spain

Re: 3D Flocking example - flying objects behaviour

Postby freezer » 04 Dec 2013, 20:10

I'll have to dig it out I only use small hard drives...
http://www.red3d.com/cwr/boids/
freezer
Gold Boarder
Gold Boarder
 
Posts: 216

Re: 3D Flocking example - flying objects behaviour

Postby freezer » 04 Dec 2013, 21:28

Annoyingly no comments :(


Main sim step...
Code: Select all

    if(this.bStep() or not this.bPaused()) then
        this.bStep(false)
       
        local x, y, z
        local x1, y1, z1 = 0, 0, 0
        local x2, y2, z2 = 0, 0, 0
        local x3, y3, z3 = 0, 0, 0
        local vx, vy, vz = 0, 0, 0
           
        for i=0, this.nObjTot()-1 do
           
            x1, y1, z1 = this.play_04_rule_1(i)     --  fly to centre
            x2, y2, z2 = this.play_04_rule_2(i)     --  keep distance away
            x3, y3, z3 = this.play_04_rule_3(i)     --  match velocity
           
           
           
            o = table.getAt(this.tObjs(), i)
            vx = x1 + x2 + x3 + object.getAIVariable(o, "play_04_boid", "vx")
            vy = y1 + y2 + y3 + object.getAIVariable(o, "play_04_boid", "vy")
            vz = z1 + z2 + z3 + object.getAIVariable(o, "play_04_boid", "vz")
           
            object.setAIVariable(o, "play_04_boid", "vx", vx)
            object.setAIVariable(o, "play_04_boid", "vy", vy)
            object.setAIVariable(o, "play_04_boid", "vz", vz)
           
            x, y, z = object.getTranslation(o, object.kGlobalSpace)
           
            object.setTranslation(o, x+vx, y+vy, z+vz, object.kGlobalSpace)
           
        end
       
        ...


The 3 behaviour functions:
Code: Select all
function menu.play_04_rule_1 ( j )
--------------------------------------------------------------------------------
   
    local x, y, z = object.getTranslation(table.getAt(this.tObjs(), j), object.kGlobalSpace)
   
    local x1, y1, z1
    local x2, y2, z2 = 0, 0, 0
   
   for i=0, this.nObjTot()-1 do
        if(i~=j) then
            x1, y1, z1 = object.getTranslation(table.getAt(this.tObjs(), i), object.kGlobalSpace)
            x2 = x2 + x1
            y2 = y2 + y1
            z2 = z2 + z1
        end
    end
   
    x2 = x2 / (this.nObjTot()-1)
    y2 = y2 / (this.nObjTot()-1)
    z2 = z2 / (this.nObjTot()-1)
   
    local n = this.nVar1()  --250   --100
    x2 = (x2 - x) / n
    y2 = (y2 - y) / n
    z2 = (z2 - z) / n
   
    return x2, y2, z2
   
--------------------------------------------------------------------------------
end


Code: Select all
function menu.play_04_rule_2 ( j )
--------------------------------------------------------------------------------
   
   local x, y, z = object.getTranslation(table.getAt(this.tObjs(), j), object.kGlobalSpace)
    local x1, y1, z1
    local x2, y2, z2 = 0, 0, 0
    local nLen
    local cx, cy, cz = 0, 0, 0
   
   
   for i=0, this.nObjTot()-1 do
        if(i~=j) then
            x1, y1, z1 = object.getTranslation(table.getAt(this.tObjs(), i), object.kGlobalSpace)
           
            x2 = x1 - x
            y2 = y1 - y
            z2 = z1 - z
           
            nLen = math.vectorLength(x2, y2, z2)
           
            if(nLen<this.nVar2()) then   --100      10
                cx = cx - x2
                cy = cy - y2
                cz = cz - z2
               
            end
           
        end
    end
   
    return cx, cy, cz
   
--------------------------------------------------------------------------------
end


Code: Select all
function menu.play_04_rule_3 ( j )
--------------------------------------------------------------------------------
   
    local o
    local x, y, z
    o = table.getAt(this.tObjs(), j)
    x = object.getAIVariable(o, "play_04_boid", "vx")
    y = object.getAIVariable(o, "play_04_boid", "vy")
    z = object.getAIVariable(o, "play_04_boid", "vz")
   
    local x1, y1, z1
    local x2, y2, z2 = 0, 0, 0
   
   for i=0, this.nObjTot()-1 do
        if(i~=j) then
            o = table.getAt(this.tObjs(), i)
            x1 = object.getAIVariable(o, "play_04_boid", "vx")
            y1 = object.getAIVariable(o, "play_04_boid", "vy")
            z1 = object.getAIVariable(o, "play_04_boid", "vz")
           
            x2 = x2 + x1
            y2 = y2 + y1
            z2 = z2 + z1
        end
    end
   
    x2 = x2 / (this.nObjTot()-1)
    y2 = y2 / (this.nObjTot()-1)
    z2 = z2 / (this.nObjTot()-1)
   
    local n = this.nVar3()  --250 --8
    x2 = (x2 - x) / n
    y2 = (y2 - y) / n
    z2 = (z2 - z) / n
   
    return x2, y2, z2
   
--------------------------------------------------------------------------------
end


The AI play_04_boid just has 3 vars vx, vy and vz
freezer
Gold Boarder
Gold Boarder
 
Posts: 216

Re: 3D Flocking example - flying objects behaviour

Postby juaxix » 10 Dec 2013, 17:13

Thanks a lot for your examples @freezer :)
do they run only with an origin in 0,0,0? , i'm trying the source in other position but it doesnt fit well...
User avatar
juaxix
Platinum Boarder
Platinum Boarder
 
Posts: 328
Location: Spain


Return to Game programming