forked from: Boid
// forked from wanson's Boid
package {
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.Event;
[SWF(width="400", height="400", backgroundColor="0xddddff")]
public class BoidDemo extends Sprite {
private const NUMBOIDS:int = 80;
private var boids:Array = new Array();
private var sprites:Array = new Array();
public function BoidDemo() {
addEventListener(Event.ENTER_FRAME, onEnterFrame);
var i:int;
for (i = 0; i < NUMBOIDS; i++) {
var b:Boid = new Boid();
const ph:Number = i * 2.0 * Math.PI / NUMBOIDS;
b.px = 200 + 90 * Math.cos(ph) * Math.sin(ph);
b.py = 200 + 40 * Math.sin(ph);
b.vx = 90 * Math.cos(ph + Math.PI / 2 + 1);
b.vy = 40 * Math.sin(ph + Math.PI / 2 + 1);
boids[i] = b;
sprites[i] = new Sprite();
var g:Graphics = sprites[i].graphics;
g.lineStyle(1, 0x0055ff);
g.moveTo(4, 0); g.lineTo(-3, -3);
g.lineTo(-3, 3); g.lineTo(4, 0); g.lineTo(-8, 0);
sprites[i].x = b.px;
sprites[i].y = b.py;
}
for (i = 0; i < NUMBOIDS; i++)
this.addChild(sprites[i]);
//this.filters = [new GlowFilter(0xff5555, 1.0, 4, 4)];
}
public function onEnterFrame(ev:Event) : void { frame(); }
public function frame() : void {
var b:Boid;
var i:int;
for (i = 0; i < NUMBOIDS; i++) {
b = boids[i];
b.force(boids);
}
for (i = 0; i < NUMBOIDS; i++) {
b = boids[i];
b.update();
sprites[i].x = b.px;
sprites[i].y = b.py;
sprites[i].rotation = Math.atan2(b.vy, b.vx) * 180 / Math.PI;
}
}
}
}
class Boid {
public var px:Number, py:Number;
public var vx:Number, vy:Number;
private var ax:Number, ay:Number;
public function Boid() {}
public function force(boids:Array) : void {
// find the nearlest neighbor
var nearlest:Boid = null;
var dx:Number, dy:Number;
var dist2:Number;
var mindist2:Number = Number.MAX_VALUE;
var i:String;
var b:Boid;
var count:int = 0;
var cx:Number = 0, cy:Number = 0;
for (i in boids) {
b = boids[i];
if (b == this)
continue;
dx = b.px - px; dy = b.py - py;
dist2 = dx * dx + dy * dy;
if (dist2 < mindist2) {
mindist2 = dist2;
nearlest = b;
}
if (dist2 < 1500) {
cx += b.px; cy += b.py;
count++;
}
}
if (nearlest == null)
return;
ax = ay = 0;
var npx:Number = nearlest.px;
var npy:Number = nearlest.py;
var nvx:Number = nearlest.vx;
var nvy:Number = nearlest.vy;
dx = (npx - px); dy = (npy - py);
dist2 = dx * dx + dy * dy;
if (dist2 > 1500)
return;
// Separation
var dist:Number = Math.sqrt(dist2);
ax += dx / dist * (dist - 25) * 0.5;
ay += dy / dist * (dist - 25) * 0.5;
// Alignment
ax += (nvx - vx) * 0.2; ay += (nvy - vy) * 0.2;
// Cohesion
dx = (cx/count - px); dy = (cy/count - py);
ax += dx * 0.1; ay += dy * 0.1;
ax += 3 * (Math.random() - 0.5); ay += 3 * (Math.random() - 0.5);
// boundary
if (px < 50) ax += (50 - px) * 0.1;
else if (px > 350) ax += (350 - px) * 0.1;
if (py < 50) ay += (50 - py) * 0.1;
else if (py > 350) ay += (350 - py) * 0.1;
}
public function update() : void
{
px += vx * (1.0/12); py += vy * (1.0/12);
vx += ax * (1.0/12); vy += ay * (1.0/12);
// speed limit
var v:Number = Math.sqrt(vx * vx + vy * vy);
if (v > 25) {
vx = vx / v * 25; vy = vy / v * 25;
} else if (v < 8) {
vx = vx / v * 8; vy = vy / v * 8;
}
}
}