ants

by demouth forked from Ant (diff: 109)
Stageクリックで蟻をおびき寄せる
蟻の行列
♥0 | Line 224 | Modified 2010-07-25 21:27:50 | MIT License
play

ActionScript3 source code

/**
 * Copyright demouth ( http://wonderfl.net/user/demouth )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/bi6J
 */

//Stageクリックで蟻をおびき寄せる
// forked from demouth's Ant
// 蟻の行列
// forked from demouth's Crowd
package {
    import flash.events.MouseEvent;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.display.StageQuality;
    import flash.events.Event;
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.utils.getTimer;
    
    [SWF(frameRate='60' , backgroundColor="0xFFFFFF")]
    public class FlashTest extends Sprite {
        private var ant:Ant;
        private var mouse:Ant;
        private var ants:Vector.<Ant>;
        private const NUM:int = 300;
        private const NUM_BLOCK:int = 10;
        private var block:Array = [];
        private var isMouseDown:Boolean = false;
        
        public function FlashTest() {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init)
        }
        
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            this.stage.quality = StageQuality.LOW;
            this.stage.scaleMode = StageScaleMode.NO_SCALE;
            this.stage.align = StageAlign.TOP_LEFT;
            
            this.ants = new Vector.<Ant>();
            this.mouse = new Ant();
            this.add();
            
            this.stage.addEventListener( Event.ENTER_FRAME , enterFrameHandler);
            this.stage.addEventListener(MouseEvent.MOUSE_DOWN , mouseDownHandler);
            this.stage.addEventListener(MouseEvent.MOUSE_UP   , mouseUpHandler);
            
        }
        
        private function enterFrameHandler(event:Event):void 
        {
            
            
            this.graphics.clear();
            
            this.mouse.x = this.stage.mouseX;
            this.mouse.y = this.stage.mouseY;
            
            var l:int = this.ants.length;
            
            if( !this.isMouseDown ) this.add();
            this.remove();
            
            for (var i:int = 0; i < l; i++) 
            {
                this.ants[i].move();
            }
            this.draw();
            
            
            this.changeTarget();
            if ( this.isMouseDown ) this.lure();
        }
        
        private function mouseDownHandler(e:MouseEvent):void 
        {
            this.isMouseDown = true;
        }
        
        private function mouseUpHandler(e:MouseEvent):void 
        {
            this.isMouseDown = false;
        }
        
        private function add():void
        {
            var ant:Ant = new Ant();
            var prevAnt:Ant;
            if( this.ants.length <= 0 ) prevAnt = this.mouse
            else prevAnt = this.ants[this.ants.length-1];
            ant.setTarget( prevAnt );
            
            if ( this.ants.length > 1 && Math.abs( prevAnt.x - this.stage.mouseX ) + Math.abs( prevAnt.y - this.stage.mouseY ) < 10 ) return;//あまり動いていなければ追加しない
            
            this.ants.push( ant );
            ant.x = this.stage.mouseX;
            ant.y = this.stage.mouseY;
            ant.angle = Math.atan2(prevAnt.y-ant.y,prevAnt.x-ant.x);
        }
        
        private function remove():void
        {
            if( this.ants.length > NUM )
            {
                this.ants.splice(0,1);
            }
        }
        
        private function draw():void
        {
            var g:Graphics = this.graphics;
            var l:int = this.ants.length;
            for (var i:int = 0; i < l; i++) 
            {
                var ant:Ant = this.ants[i];
                var toX:Number = ant.x + Math.cos( ant.angle ) * 4 ;
                var toY:Number = ant.y + Math.sin( ant.angle ) * 4 ;
                
                g.lineStyle( 1 , 0);
                g.moveTo( ant.x , ant.y );
                g.lineTo( toX , toY );
                g.drawCircle( ant.x , ant.y , 1 );
                g.drawCircle( toX , toY , 1 );
            }
        }
        
        private function changeTarget():void
        {
            var s:uint = NUM_BLOCK;
            var w:Number = this.stage.stageWidth;
            var h:Number = this.stage.stageHeight;
            var spanW:Number = w / s;
            var spanH:Number = h / s;
            var blockX:uint;
            var blockY:uint;
            var l:int = this.ants.length;
            
            this.block = [];
            for (i = 0; i < l; i++) 
            {
                blockX = int( this.ants[i].x / spanW );
                blockY = int( this.ants[i].y / spanH );
                
                this.ants[i].blockX = blockX;
                this.ants[i].blockY = blockY;
                if( !this.block[blockX])this.block[blockX] = [];
                if( !this.block[blockX][blockY] )this.block[blockX][blockY] = [];
                this.block[blockX][blockY].push( this.ants[i] );
            }
            
            
            for (var i:int = 0; i < l; i++) 
            {
                if ( !this.ants[i].isChangePhase ) continue;
                
                blockX = int( this.ants[i].x / spanW );
                blockY = int( this.ants[i].y / spanH );
                var t:Array = [];//targetになり得るAnt
                for (var j:int = blockX-2;j<blockX+2;j++)
                {
                    for(var k:int = blockY-2;k<blockY+2;k++)
                    {
                        if( !this.block[j])continue;
                        if( !this.block[j][k] )continue;
                        t = t.concat(this.block[j][k]);
                    }
                }
                var numAnts:uint = t.length;
                if( numAnts <= 0 ) continue;
                var index:uint = int( numAnts * Math.random() );
                
                if ( t[index] && t[index] != this.ants[i] )
                {
                    this.ants[i].setTarget( t[index] as Ant );
                }
            }
        }
        
        private function lure():void
        {
            
            var s:uint = NUM_BLOCK;
            var w:Number = this.stage.stageWidth;
            var h:Number = this.stage.stageHeight;
            var spanW:Number = w / s;
            var spanH:Number = h / s;
            var blockX:uint = int( this.stage.mouseX / spanW );
            var blockY:uint = int( this.stage.mouseY / spanH );
            
            var t:Array = [];
            for (var j:int = blockX-1;j<blockX+1;j++)
            {
                for(var k:int = blockY-1;k<blockY+1;k++)
                {
                    if ( !this.block[j]) continue;
                    if ( !this.block[j][k] ) continue;
                    var numBlock:uint = this.block[j][k].length;
                    for (var i:int = 0; i < numBlock; i++)
                    {
                        this.block[j][k][i].setTarget( this.mouse );
                    }
                }
            }
            
        }

    }
}

class Ant
{
    
    public var x:Number = 0;
    public var y:Number = 0;
    public var blockX:uint = 0;
    public var blockY:uint = 0;
    public var angle:Number = 0;
    public var speed:Number = 0;
    public var isChangePhase:Boolean = false;
    private const C:uint = 50;
    private var phaseCount:uint = C;
    private var target:Ant;
    
    public function Ant() 
    {
    }
    
    public function setTarget(target:Ant):void
    {
        this.target = target;
    }
    public function move():void
    {
        
        if ( this.target )
        {
            var diffX:Number = this.target.x - this.x;
            var diffY:Number = this.target.y - this.y;
            var diff:Number = Math.sqrt( diffX * diffX + diffY * diffY );//直線上の距離
            
            if ( diff > 3 )//一定の距離以上の時は角度を変更する
            {
                var nowAngle:Number = this.angle;
                var toTargetAngle:Number = Math.atan2( diffY , diffX );
                nowAngle += Math.PI * 2;
                toTargetAngle += Math.PI * 2;
                nowAngle %= Math.PI * 2;
                toTargetAngle %= Math.PI * 2;
                
                if ( Math.abs( nowAngle - toTargetAngle ) > Math.PI )
                {
                    if ( nowAngle < toTargetAngle ) nowAngle += Math.PI * 2
                    else nowAngle -= Math.PI * 2;
                }
                var angleStepRatio:Number = 0.9 + Math.random() * 0.1;
                this.angle = nowAngle * angleStepRatio + toTargetAngle * (1-angleStepRatio) ;
            }
            
            //スピードを変更する
            this.speed *= 0.94;
            if ( diff > 5 ) this.speed += 0.04;
            
        }
        
        var moveX:Number = Math.cos( this.angle ) * this.speed;
        var moveY:Number = Math.sin( this.angle ) * this.speed;
        
        this.x += moveX;
        this.y += moveY;
        
        this.phaseCount--;
        if ( this.phaseCount <= 0 ) {
            this.phaseCount = C;
            this.isChangePhase = true;
        }else{
            this.isChangePhase = false;
        }
        
    }
    
}