forked from: Boid
// forked from wanson's Boid
package {
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.Event;
import flash.filters.*;
import flash.events.MouseEvent;
[SWF(width="400", height="400", backgroundColor="0x000000")]
public class BoidDemo extends Sprite {
private const NUMBOIDS:int = 70;
private var boids:Array = new Array();
private var sprites:Array = new Array();
private var isBoidOn:Boolean = true;
public function BoidDemo() {
addEventListener(Event.ENTER_FRAME, onEnterFrame);
stage.addEventListener(MouseEvent.CLICK, onClick);
var i:int;
for (i = 0; i < NUMBOIDS; i++) {
var b:Boid = new Boid();
resetBoid(b);
boids[i] = b;
sprites[i] = new Sprite();
var g:Graphics = sprites[i].graphics;
/*g.lineStyle(1, 0xffffff);
g.moveTo(4, 0); g.lineTo(-3, -3);
g.lineTo(-3, 3); g.lineTo(4, 0); g.lineTo(-8, 0);*/
g.beginFill(0x666666);
g.drawCircle(0, 0, 10);
g.endFill();
sprites[i].x = b.px;
sprites[i].y = b.py;
this.addChild(sprites[i]);
}
this.filters = [new GlowFilter(0xffffff, 2.0, 10, 10)];
}
public function resetBoid(b: Boid):void
{
b.init(200 * Math.random() + 100,
10 * Math.random()+200,
30 * (Math.random() - 0.5),
30 * (Math.random() - 0.5),
50 * Math.random() + 50);
}
public function onClick(ev:Event=null) : void {
if (isBoidOn)
isBoidOn=false;
else
isBoidOn=true;
}
public function onEnterFrame(ev:Event=null) : void {
for (var i:int = 0; i < NUMBOIDS; i++) {
var b:Boid = boids[i];
if (isBoidOn)
b.force(boids);
b.update();
sprites[i].x = b.px;
sprites[i].y = b.py;
sprites[i].rotation = Math.atan2(b.vy, b.vx) * 180 / Math.PI;
sprites[i].alpha = b.timer/20;
if (b.timer==0)
resetBoid(b);
}
}
}
}
class Boid {
public var px:Number, py:Number;
public var vx:Number, vy:Number;
private var ax:Number, ay:Number;
public var timer:int;
public function Boid() {}
public function init(gx:Number, gy:Number, gvx:Number, gvy:Number, gtimer:int):void {
px=gx; py=gy;
vx=gvx;
vy=gvy;
ax=ay=0;
//ax=-gvx; ay=-gvy;
timer=gtimer;
}
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 += 10 * (Math.random() - 0.5); ay += 10 * (Math.random() - 0.5);
// boundary
if (px < 50) ax += (50 - px) * 0.05;
else if (px > 350) ax += (350 - px) * 0.05;
if (py < 50) ay += (50 - py) * 0.05;
else if (py > 350) ay += (350 - py) * 0.05;
}
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 > 17) {
vx = vx / v * 17; vy = vy / v * 17;
} else if (v < 8) {
vx = vx / v * 8; vy = vy / v * 8;
}
timer--;
}
}