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

in Examples Posts: 116

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
``````
Tagged: