fc2ブログ

Boidアルゴリズム(3D)

2010-04-22 | 11:09

群れの動きをシミュレーションするBoidのアルゴリズム。 http://www.vergenet.net/~conrad/boids/pseudocode.html
ASで実装してみたがパラメタ調整が難しくてなかなかそれらしく見えない。




package {
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
        [SWF(width='600',height='400',backgroundColor='0x0',framerate='5')]
    public class BoidSimulation extends Sprite {
        private var N:int = 80;
        private var boids:Array = [];
        private var rad:Number = 0;
        private var leader:Boid = new Boid(0, 0xff, 4);
        private var cnt:int=0;
        public function BoidSimulation( ) {
            leader.x = 250;
            leader.y = 100;
            leader.z = 0;
            var velocity:Vector3D = new Vector3D();
            trace(velocity);
            leader.velocity = velocity;
            addChild(leader);
            for(var i:int = 0 ; i < N ; i++){
                var b:Boid = new Boid(i, 0xff0000, 2);
                addChild(b);
                boids.push(b);
            }
            addEventListener(Event.ENTER_FRAME, onEnterFrame);
        }

        public function onEnterFrame(event:Event):void {
            rad++;
            leader.velocity.x = Math.cos(rad/180*Math.PI)*10;
            leader.velocity.z = Math.sin(rad/180*Math.PI)*10;

            leader.move();
            if(leader.x  > 600 ||
                    leader.x  < 0)
                leader.velocity.x *= -1;
            if(leader.y > 600 ||
                    leader.y < 0)
                leader.velocity.y *= -1;
            if(leader.z  > 500 ||
                    leader.z  < 0)
                leader.velocity.z *= -1;

            for each (var b:Boid in boids){	
                b.velocity = b.velocity.add(cohesion(b));
                b.velocity = b.velocity.add(separation(b));
                b.velocity = b.velocity.add(alignment(b));
                b.velocity = b.velocity.add(tendToPlace(b,leader.position));
                //trace("velocity=",b.velocity);
                b.move();
            }
        }

        private function cohesion(boid:Boid):Vector3D{
            var pcJ:Vector3D = new Vector3D();

            for each (var b:Boid in boids){	
                if(b != boid){
                    pcJ.add(b.position);
                }
            }

            pcJ.scaleBy(1/(N-1));

            pcJ = pcJ.subtract(boid.position);
            pcJ.scaleBy(1/300);
            //trace("cohesion=",pcJ);
            return pcJ;
        }

        private function  separation(boid:Boid):Vector3D{
            var c:Vector3D = new Vector3D();

            for each (var b:Boid in boids){	
                if(b != boid){
                    if (Vector3D.distance(b.position, boid.position ) < 50) {
                        var temp:Vector3D = b.position.subtract(boid.position);
                        c = c.subtract(temp);
                    }
                }
            }
            c.scaleBy(1/5);
            //trace("separation=",c);

            return c;
        }

        private function alignment(boid:Boid):Vector3D{
            var pvJ:Vector3D = new Vector3D();

            for each (var b:Boid in boids){	
                if(b != boid){
                    pvJ = pvJ.add(b.velocity);
                    //trace(pvJ.x);
                }
            }

            pvJ.scaleBy(1 / (N-1));

            pvJ = pvJ.subtract(boid.velocity);
            pvJ.scaleBy(1/500);
            //trace("alignment=",pvJ);
            return pvJ;
        }

        private function tendToPlace(boid:Boid, v:Vector3D):Vector3D{
            var place:Vector3D = v.clone();
            place = place.subtract(boid.position);

            place.scaleBy(1/150);
            return place;
        }
    }
}

import flash.display.*;
import flash.geom.*;

class Boid extends Sprite{
    private var _velocity:Vector3D = new Vector3D();
    private var MAX_SPEED_X:int = 6;
    private var MAX_SPEED_Y:int = 6;
    private var MAX_SPEED_Z:int = 6;
    public var id:int;

    public function Boid(id:int, color:int, r:int){
        this.id = id;
        this.x = Math.random()*600;
        this.y = Math.random()*600;
        this.z = Math.random()*600;

        this._velocity.x = Math.random()/100;
        this._velocity.y = Math.random()/100;
        this._velocity.z = Math.random()/100;

        //trace(_velocity.x);

        graphics.beginFill(color);
        graphics.drawCircle(0,0,r);
        graphics.endFill();
    }

    public function move():void{

        this.x += this._velocity.x;
        this.y += this._velocity.y;
        this.z += this._velocity.z;

    }

    public function get position():Vector3D{
        return new Vector3D(this.x, this.y, this.z);
    }

    public function get velocity():Vector3D{
        return this._velocity;
    }

    public function set velocity(v:Vector3D):void{
        if(v.x > MAX_SPEED_X)
            v.x = MAX_SPEED_X;
        if(v.x < -MAX_SPEED_X)
            v.x = -MAX_SPEED_X;
        if(v.y > MAX_SPEED_Y)
            v.y = MAX_SPEED_Y;
        if(v.y < -MAX_SPEED_Y)
            v.y = -MAX_SPEED_Y;
        if(v.z > MAX_SPEED_Z)
            v.z = MAX_SPEED_Z;
        if(v.z < -MAX_SPEED_Z)
            v.z = -MAX_SPEED_Z;
        this._velocity = v;
    }
}


スポンサーサイト