flash on 2010-7-3

by fakestar0826
衝突判定
「詳解 ActionScript 3.0 アニメーション」より
写経であーる。
♥0 | Line 234 | Modified 2010-07-03 13:05:10 | MIT License
play

ActionScript3 source code

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

//衝突判定
//「詳解 ActionScript 3.0 アニメーション」より
//写経であーる。
package {
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.text.TextField;
    import flash.utils.getTimer;
    
    public class FlashTest extends Sprite {
        private const GRID_SIZE:Number = 50;
        private const RADIUS:Number = 25;
        
        private var _balls:Array;
        private var _grid:Array;
        private var _numBalls:int = 100;
        private var _numChecks:int = 0;
        
        public function FlashTest() {
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            
            makeBalls();
            drawGrid();
            
            var startTime:int;
            var elapsed:int;
            var i:int;
            
            startTime = getTimer();
            for(i = 0;i < 10;i++)
            {
                makeGrid();
                AssignBallsToGrid();
                checkGrid();
            }
            elapsed = getTimer() - startTime;
            
            
            var tf:TextField = new TextField();
            tf.text = "グリッド判定時間:" + elapsed + "ms";
            tf.background = true;
            tf.backgroundColor = 0xFFFFFF;
            tf.autoSize = "left";
            tf.x = 50;
            tf.y = 440;
            tf.selectable = false;
            stage.addChild(tf);
            
            startTime = getTimer();
            for(i = 0;i < 10;i++)
            {
                basicCheck();
            }
            elapsed = getTimer() - startTime;
            
            var tf2:TextField = new TextField();
            tf2.text = "通常判定時間:" + elapsed + "ms";
            tf2.background = true;
            tf2.backgroundColor = 0xFFFFFF;
            tf2.autoSize = "left";
            tf2.x = 250;
            tf2.y = 440;
            tf2.selectable = false;
            stage.addChild(tf2);
        }
        
        public function makeBalls():void
        {
            _balls = new Array();
            for(var i:int = 0;i < _numBalls;i++)
            {
                var ball:Ball = new Ball(Math.random() * RADIUS);
                ball.x = Math.random() * stage.stageWidth;
                ball.y = Math.random() * stage.stageHeight;
                addChild(ball);
                _balls.push(ball);
            }

        }
        
        public function makeGrid():void
        {
            _grid = new Array();
            for(var i:int = 0;i < stage.stageWidth / GRID_SIZE;i++)
            {
                _grid[i] = new Array();
                for(var j:int = 0;j < stage.stageHeight / GRID_SIZE;j++)
                {
                    _grid[i][j] = new Array();
                }
            }
        }
        
        public function drawGrid():void
        {
            graphics.lineStyle(0, 0.5);
            for(var i:int = 0;i <= stage.stageWidth;i += GRID_SIZE)
            {
                graphics.moveTo(i, 0);
                graphics.lineTo(i, stage.stageHeight);
            }
            for(i = 0;i <= stage.stageHeight;i += GRID_SIZE)
            {
                graphics.moveTo(0, i);
                graphics.lineTo(stage.stageWidth, i);
            }
        }
        
        public function AssignBallsToGrid():void
        {
            for(var i:int = 0;i < _numBalls;i++)
            {
                var ball:Ball = _balls[i] as Ball;
                //ここで、ひとつのグリッドに2個以上のBallが入る場合がある。
                //また、ひとつもBallが入ってない場合もある。
                var xpos:int = Math.floor(ball.x / GRID_SIZE);
                var ypos:int = Math.floor(ball.y / GRID_SIZE);
                _grid[xpos][ypos].push(ball);
            }
        }
        
        public function checkGrid():void
        {
            for(var i:int = 0;i < _grid.length;i++)
            {
                for(var j:int = 0;j < _grid[i].length;j++)
                {
                    //グリッド内でのチェック
                    checkOneCell(i, j);
                    //隣接するグリッド間のチェック
                    checkTwoCells(i, j, i + 1, j);
                    checkTwoCells(i, j, i - 1, j + 1);
                    checkTwoCells(i, j, i, j + 1);
                    checkTwoCells(i, j, i + 1, j + 1);
                }
            }
        }
        
        public function checkOneCell(x:int, y:int):void
        {
            var cell:Array = _grid[x][y] as Array;
            //グリッド内のBallを引き出し、衝突判定メソッドを呼び出す。
            for(var i:int = 0;i < cell.length - 1;i++)
            {
                var ballA:Ball = cell[i] as Ball;
                for(var j:int = i + 1;j < cell.length;j++)
                {
                    var ballB:Ball = cell[j] as Ball;
                    checkCollision(ballA, ballB);
                }
            }
        }
        
        public function checkTwoCells(x1:int, y1:int, x2:int, y2:int):void
        {
            if(x2 < 0) return;
            if(x2 >= _grid.length) return;
            if(y2 >= _grid[x2].length) return;
            
            var cell0:Array = _grid[x1][y1] as Array;
            var cell1:Array = _grid[x2][y2] as Array;
            //グリッド内のBallを引き出し、衝突判定メソッドを呼び出す。
            for(var i:int = 0;i < cell0.length;i++)
            {
                var ballA:Ball = cell0[i] as Ball;
                for(var j:int = 0;j < cell1.length;j++)
                {
                    var ballB:Ball = cell1[j] as Ball;
                    checkCollision(ballA, ballB);
                }
            }
        }
        
        public function checkCollision(ballA:Ball, ballB:Ball):void
        {
            _numChecks++;
            var dx:Number = ballB.x - ballA.x;
            var dy:Number = ballB.y - ballA.y;
            var dist:Number = Math.sqrt(dx * dx + dy * dy);
            //Ball間の距離で衝突判定。
            if(dist < ballA.radius + ballB.radius)
            {
                ballA.color = 0xFF0000;
                ballB.color = 0xFF0000;
            }

        }
        
        public function basicCheck():void
        {
            for(var i:int = 0;i < _balls.length - 1;i++)
            {
                var ballA:Ball = _balls[i] as Ball;
                for(var j:int = i + 1;j < _balls.length;j++)
                {
                    var ballB:Ball = _balls[j] as Ball;
                    checkCollision(ballA, ballB);
                }

            }

        }


    }
}

import flash.display.Sprite;

class Ball extends Sprite
{
    private var _color:uint;
    private var _radius:Number;
    private var _vx:Number;
    private var _vy:Number;
    
    public function Ball(radius:Number, color:uint = 0xFFFFFF)
    {
        _radius = radius;
        _color = color;
        draw();
    }
    
    public function draw():void
    {
        graphics.clear();
        graphics.lineStyle(0);
        graphics.beginFill(_color, 0.5);
        graphics.drawCircle(0, 0, _radius);
        graphics.endFill();
        graphics.drawCircle(0, 0, 1);
    }
    
    public function update():void
    {
        x += _vx;
        y += _vy;
    }
    
    public function set color(value:uint):void
    {
        _color = value;
        draw();
    }
    
    public function get color():uint
    {
        return _color;
    }
    
    public function set radius(value:Number):void
    {
        _radius = value;
        draw();
    }
    
    public function get radius():Number
    {
        return _radius;
    }
    
    public function set vx(value:Number):void
    {
        _vx = value;
    }
    
    public function get vx():Number
    {
        return _vx;
    }
    
    public function set vy(value:Number):void
    {
        _vy = value;
    }
    
    public function get vy():Number
    {
        return _vy;
    }
}

Forked