Imagine a 2D space occupied by moving birds. We refer to them as 'boids'- a pun on bird/droid and on New Yorker's pronunciation quirks! Each is only aware of close neighbours, and responds via simple reflexes and learned responses. It is attracted to close neighbours, but at close range avoids collisions and obstacles or walls. And out of this in real life something magic emerges.
As a programming task we have to keep track of each boid's x, y positions and velocities. We calculate the acceleration from simple rules, and update velocities and position. But potentially there is a LOT of calculating to do. In a real flock near here they regularly see up to estimated 1,000,000 individuals. Luckily no one bird interacts with all those- which would be intractable- but you have to think of ways a bird will interact only directly with immediate neighbours- even though they may change!
Below is my current version. You might visit the thread at Liberty BASIC for further ideas.
' ******************************************** ' ** ** ' ** tenochBoids4.bas 16/03/21 ** ' ** ** ' ** create a field of flocking boids ** ' ** ** ' ******************************************** nomainwin WindowWidth =1120 WindowHeight = 630 ' Each boid represented in a csv string of x, y, vx, vy ' x/y onscreen if in o...600. Velocity of 1 represents one pixel per cycle. global xCG, yCG ' coordinates of centre of gravity of flock N = 50 ' number of boids dim boid$( N) open "Tenochtitlanuk Boids" for graphics_nsb as #wg #wg "trapclose quit" #wg "down ; size 10 ; fill 80 80 255" loadbmp "scr", "sky.bmp" gosub [createBoidField] [next] ' cycle the updates gosub [drawBoidField] gosub [updateBoidField] scan goto [next] ' __________________________________________________________ [createBoidField] for i =0 to N -1 x = 50 +1000 *rnd( 1) y = 50 + 500 *rnd( 1) vx = 2 + 8 *rnd( 1) -4 vy = 2 + 8 *rnd( 1) -4 boid$( i) =str$( x) +"," +str$( y) +"," +str$( vx) +"," +str$( vy) next i return [drawBoidField] ' draw current flock. #wg "cls ; drawbmp scr 1 1" #wg "color red ; size 5 ; up ; goto 2 2 ; down ; box 1105 597 ; up" for i =0 to N -1 call drawBoid boid$( i) scan next i return [updateBoidField] ' calculate new boid flock. gosub [findCofG] ' find xCG, yCG of centre of mass for K =0 to N -1 x =val( word$( boid$( K), 1,",")) y =val( word$( boid$( K), 2,",")) R$ =rule1$( K) vx =val( word$( boid$( K), 3, ",")) -( x -xCG) /10000'-1e-1 *val( word$( R$, 1, ",")) *sin( val( word$( R$, 2, ","))) ' *angle fn.) vy =val( word$( boid$( K), 4, ",")) -( y -yCG) / 6000'-1e-1 *val( word$( R$, 1, ",")) *cos( val( word$( R$, 2, ","))) vx =0.9999 *vx vy =0.9999 *vy x =x +vx y =y +vy if x <=10 or x >=1090 then vx =0 -0.9 *vx ' implements ricochets off sides. if y <=15 or y >= 585 then vy =0 -0.9 *vy ' could instead wrap top/bottom and left/right- toroid world. boid$( K) =str$( x) +"," +str$( y) +"," +str$( vx) +"," +str$( vy) scan next K return [findCofG] ' place CofG position in global xCG, yCG. xCG =0: yCG =0 for f =0 to N -1 xCG =xCG +val( word$( boid$( f), 1, ",")) yCG =yCG +val( word$( boid$( f), 2, ",")) next f xCG =( xCG /N +500) /2 yCG =( yCG /N +300) /2 return function rule1$( K) ' accelerate towards centre of mass of flock. dx =val( word$( boid$( K), 1, ",")) -xCG dy =val( word$( boid$( K), 2, ",")) -yCG R =( dx^2 +dy^2)^0.5 angle =Atan2( dy, dx) rule$ =str$( R) +"," +str$( angle) ' return a string with magnitude and angle of accn towards CofG end function sub drawBoid i$ ' draw an individual boid #wg "color darkblue" ' draw boid #wg "size 10 ; down" x =val( word$( i$, 1, ",")) y =val( word$( i$, 2, ",")) #wg "set "; int( x); " "; int( y) vx =val( word$( i$, 3, ",")) vy =val( word$( i$, 4, ",")) magn =( vx^2 +vy^2)^0.5 dirn =Atan2( vy, vx) nx =x +vx ny =y +vy #wg "color black" ' draw tail, length proportional to velocity and along track #wg "size 1" #wg "goto "; x -4 *vx; " "; y -4 *vy end sub Function Atan2( y, x) If x = 0 Then If y < 0 Then Atan2 = -1.5707963267948967 Else Atan2 = 1.5707963267948967 End If Else chk = atn(y/x) If x < 0 Then If y < 0 Then chk = chk - 3.1415926535897932 Else chk = chk + 3.1415926535897932 End If End If Atan2 = chk End If 'thanks Andy Amaya ( one of several versions I use) End Function sub quit h$ close #h$ end end sub