Hey, guys. I have a problem with my first AI project. It's about flocking. The problem is, it looks so unnatural. They tend to flock with no more than 2 or 3 boids. SWF : http://megaswf.com/view/03279d52b96a29a5590e45eff91e20a3.html Yes, I've read the boid's page. I've understood the algorithm ( I think) but I failed to implement it. Dunno whats wrong with my code. Okay, my approach for this AI is : 1) Find the "desired" direction based on separation, alignment, and alignment rule 2) Steer to "desired" direction However, this is my code. It's done in AS 3 (FYI I've just start learning AS 3 few days ago). For simplicity, I set all the boids speed to a same value. So we will find the desired direction :
function Flock_Calc(me:MovieClip):void {
//begins flocking AI
var Dx:Number = 0; //Resultant Vector for X axis
var Dy:Number = 0; //Resultant Vector for Y axis
var count:Number = 0;
var avgDir:Number = 0; //avg direction - for alignment rule
for(var i = 0; i<BodyArray.length; i++) {
//if the boid is me, then continue to next iteration
if(i==me.id) continue;
var dx:Number = (BodyArray.x-me.x); //distance in X axis between me and other boid
var dy:Number = (BodyArray.y-me.y);
var dr:Number = Math.sqrt(dx*dx + dy*dy); //distance
//if the boid is out of my sight, continue to next iteration
if(dr>me.sightRadius) continue;
//cohesion rule
//the farther the other boid, the stronger the desire to steer to that location
Dx += LinearFunction(dx,0,0,me.sightRadius,1); //this function returns 0 when dx = 0
Dy += LinearFunction(dy,0,0,me.sightRadius,1); //return 1 for dx = sightradius and -1 for dx = -sightradius
//alignment
avgDir += BodyArray.rotation;
count++;
//separation
//the nearer the boid, the stronger desire to steer away from that location
if(dr<=me.sepRadius) {
if(dx>0) Dx -= LinearFunction(Math.abs(dx),0,1,me.sepRadius,0); //return 1 if dx = 0 and 0 if dx = sepradius
else Dx += LinearFunction(Math.abs(dx),0,1,me.sepRadius,0);
if(dy>0) Dy -= LinearFunction(Math.abs(dy),0,1,me.sepRadius,0);
else Dy += LinearFunction(Math.abs(dy),0,1,me.sepRadius,0);
}
}
if(count > 0) {
//computing the final alignment rule
avgDir += me.rotation; //add my direction
count++;
avgDir /= count; //get the average
Dx += Math.cos(avgDir); //Math.cos returns value between -1 and 1
Dy += Math.sin(avgDir);
//the final magnitude of Dx and Dy doesnt matter since we just find for the direction
me.toRotate = Math.atan2(Dy,Dx)/Math.PI*180;
}
else me.toRotate = me.rotation;
}
Here is the steering method:
//calculate steering
me.rotation += (me.toRotate - me.rotation)*0.1;
and here is the linear function, just in case you need it
//LinearFunction()
//(y-y1)/(y2-y1) = (x-x1)/(x2-x1)
//(y-y1) = (x-x1)/(x2-x1)*(y2-y1)
// y = [(x-x1)/(x2-x1)*(y2-y1)] + y1
//LinearFunction returns y for any given x passed by valx
function LinearFunction(valx:Number,
x1:Number, y1:Number,
x2:Number, y2:Number):Number {
return (valx - x1)/(x2-x1) *(y2-y1) + y1;
}