Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Boids or group behavior in 60 lines of code

Hey there,
I managed to write a simulation that is known under the name "boids". It simulates the flocking behavior of birds. Each bird follow a couple of simple rules which modify their moving vectors. You can simply find the Wikipedia article to learn more.
I added a couple of rules, to make the boids stay in bounds of the screen and to limit their velocity.
They also follow your finger, when you move it and fly away when you tap the screen. I hope the program is simple to understand and maybe(with a couple of modifications) it could be a bult-in example for Codea? ;)) @Simeon
Here is the code:

--# Main -- Boids function setup() parameter.number("affectFac",0.1,40,10) parameter.number("goToCenterFac", 1, 16, 10) parameter.number("stayAwayFac", 1, 100, 100) parameter.number("matchVelFac", 1, 20, 12) parameter.number("goToPlaceFac", 1, 20, 12) parameter.number("stayAwayFac2", 1,20, 12) lim = 60 boids = {} for i = 1, lim do table.insert(boids, Boid(vec2(math.random(100,WIDTH-100),math.random(100,HEIGHT-100)),i)) end end function draw() background(40, 40, 50) for i, b in ipairs(boids) do b:draw() end updateBoids() end function updateBoids() v = vec2() for i, b in ipairs(boids) do v = v + goToCenter(b) / goToCenterFac v = v + stayAway(b)/stayAwayFac2 v = v + matchVel(b) /matchVelFac v = v + matchNearestVel(b)/matchVelFac*5 v = v + goToPlace(b) /goToPlaceFac v = v + stayInBounds(b) v = v * (0.9+math.random()/5) limVel(b) b.velocity = b.velocity + v/affectFac end end function goToCenter(bJ) pcJ = vec2() for i, b in ipairs(boids) do if b == bJ then else pcJ = pcJ + b.position end end pcJ = pcJ / (lim-1) return (pcJ - bJ.position)/50 end function stayAway(bJ) c = vec2() for i, b in ipairs(boids) do if b == bJ then else if bJ.position:dist(b.position) < stayAwayFac then c = c - (b.position - bJ.position)/50 end end end return c end function matchVel(bJ) pvJ = vec2() for i, b in ipairs(boids) do if b == bJ then else pvJ = pvJ + b.velocity end end pvJ = pvJ / (lim-1) return (pvJ - bJ.velocity)/50 end function matchNearestVel(bJ) distance = math.maxinteger for i, b in ipairs(boids) do if b == bJ then else if bJ.position:dist(b.position) < distance then distance = bJ.position:dist(b.position) nearestVel = b.velocity end end end return nearestVel/50 end function goToPlace(b) place = vec2(WIDTH/2, HEIGHT-300) return(place - b.position)/50 end function stayInBounds(b) c = vec2() if b.position.x < 0 then c = c + vec2(3,0) elseif b.position.x > WIDTH then c = c + vec2(-3,0) end if b.position.y < 0 then c = c + vec2(0,3) elseif b.position.y > HEIGHT then c = c + vec2(0,-3) end return c end function limVel(b) vlim = 5 len = b.velocity:len() if math.abs(len) > vlim then b.velocity = b.velocity:normalize()*vlim end end function touched(touch) v = vec2() for i, b in ipairs(boids) do touchpos = vec2(touch.x, touch.y) v = (touchpos - b.position) / 200 limVel(b) if touch.state == BEGAN then b.velocity = b.velocity - v/v:lenSqr() *200 else b.velocity = b.velocity + v end end end --# Boid Boid = class() function Boid:init(pos,n) self.position = pos self.velocity = vec2(0,0) self.num = n self.sprites = {"Space Art:Part Gray Hull 1", "Space Art:Part Green Hull 1", "Space Art:Part Red Hull 1","Space Art:Part Yellow Hull 1"} self.sprite = self.sprites[math.floor(math.random(1,#self.sprites))] end function Boid:draw() pushMatrix() self.position = self.position + self.velocity translate(self.position:unpack()) rotate(-90) rotate(math.deg(math.atan(self.velocity.y,self.velocity.x))) --rotate(self.velocity:angleBetween(vec2(0,100))) sprite(self.sprite, 0,0,20,20) text(self.num) popMatrix() end function Boid:touched(touch) end function Boid:getNum() return self.num end function Boid:getPos() return self.position end


Sign In or Register to comment.