In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

衝突判定の学習

オライリー 衝突判定の学習
/**
 * Copyright Nyarineko ( http://wonderfl.net/user/Nyarineko )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/5rQT
 */

/*オライリー 衝突判定の学習*/
package
{
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.display.DisplayObject;
    import flash.events.Event;

    public class GridCollision3 extends Sprite
    {
        private const GRID_SIZE:Number = 20;
        private var _grid_size:Number = 20;
        private const RADIUS:Number = 10;

        private var _balls:Vector.<DisplayObject>;
        private var _grid:CollisionGrid;
        private var _numBalls:int = 200;

        public function GridCollision3()
        {

            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            /*
            _grid = new CollisionGrid(stage.stageWidth,
                                      stage.stageHeight,
                                      GRID_SIZE);
                                      
            _grid.drawGrid(graphics);
            */
            //_grid_size
            makeBalls();
            _grid = new CollisionGrid(stage.stageWidth,
                                      stage.stageHeight,
                                      _grid_size);
                                      
            _grid.drawGrid(graphics);
            
            
            addEventListener(Event.ENTER_FRAME, onEnterFrame);
        }

        private function onEnterFrame(event:Event):void
        {

            // 個々のボールについて速度を足す
            updateBalls();

            // チェックが必要なボールを調べる
            _grid.check(_balls);

            var numChecks:int = _grid.checks.length;
            for (var j:int = 0; j < numChecks; j += 2)
            {

                // 2つずつ調べる
                checkCollision(_grid.checks[j] as Ball,
                               _grid.checks[j + 1] as Ball);
            }
        }
        
        private function makeBalls():void
        {
            var max:Number = 0;
            // 全てのボールを生成する
            _balls = new Vector.<DisplayObject>(_numBalls);
            for (var i:int = 0; i < _numBalls; i++)
            {

                //var ball:Ball = new Ball(RADIUS);
                var ball:Ball = new Ball(Math.random() * 10 + 5);
                ball.x = Math.random() * stage.stageWidth;
                ball.y = Math.random() * stage.stageHeight;
                ball.vx = Math.random() * 4 - 2;
                ball.vy = Math.random() * 4 - 2;
                
                if(ball.radius > max) max = ball.radius;
                addChild(ball);
                _balls[i] = ball;
            }
            _grid_size = max*2;
        }

        private function updateBalls():void
        {

            for (var i:int = 0; i < _numBalls; i++)
            {

                // ボールを移動し、壁に跳ね返らせる
                var ball:Ball = _balls[i] as Ball;

                ball.update();

                if (ball.x < RADIUS)
                {
                    ball.x = RADIUS;
                    ball.vx *= -1;
                }
                else if (ball.x > stage.stageWidth - RADIUS)
                {
                    ball.x = stage.stageWidth - RADIUS;
                    ball.vx *= -1;
                }

                if (ball.y < RADIUS)
                {
                    ball.y = RADIUS;
                    ball.vy *= -1;
                }
                else if (ball.y > stage.stageHeight - RADIUS)
                {
                    ball.y = stage.stageHeight - RADIUS;
                    ball.vy *= -1;
                }

                ball.color = 0xffffff;
            }
        }

        private function checkCollision(ballA:Ball, ballB:Ball):void
        {

            // 2つのボールの衝突判定を行う
            var dx:Number = ballB.x - ballA.x;
            var dy:Number = ballB.y - ballA.y;
            var dist:Number = Math.sqrt(dx * dx + dy * dy);

            if (dist < ballA.radius + ballB.radius)
            {
                ballA.color = 0xff0000;
                ballB.color = 0xff0000;
            }
        }
    }
}

import flash.display.Sprite;
    
class Ball extends Sprite
{
   private var _color:uint;
    private var _radius:Number;
    private var _vx:Number = 0;
    private var _vy:Number = 0;

    public function Ball(radius:Number, color:uint = 0xffffff)
    {
        _radius = radius;
        _color = color;
        draw();
    }

    private function draw():void
    {
        // 中心に点のある円を描く
        graphics.clear();
        graphics.lineStyle(0);
        graphics.beginFill(_color, .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;
    }
}

import flash.display.DisplayObject;
import flash.display.Graphics;
import flash.events.EventDispatcher;

class CollisionGrid extends EventDispatcher
{

    private var _checks:Vector.<DisplayObject>;
    private var _grid:Vector.<Vector.<DisplayObject>>;
    private var _gridSize:Number;
    private var _height:Number;
    private var _numCells:int;
    private var _numCols:int;
    private var _numRows:int;
    private var _width:Number;
    public function CollisionGrid(width:Number,
                                  height:Number,
                                  gridSize:Number)

    {
        _width = width;
        _height = height;
        _gridSize = gridSize;
        _numCols = Math.ceil(_width / _gridSize);
        _numRows = Math.ceil(_height / _gridSize);
        _numCells = _numCols * _numRows;
    }    

    public function drawGrid(graphics:Graphics):void
    {
        // グリッドを表す線を描く
        graphics.lineStyle(0, .5);

        for (var i:int = 0; i <= _width; i += _gridSize)
        {
            graphics.moveTo(i, 0);
            graphics.lineTo(i, _height);
        }
        for (i = 0; i <= _height; i += _gridSize)
        {
            graphics.moveTo(0, i);
            graphics.lineTo(_width, i);
        }            
    }

    public function check(objects:Vector.<DisplayObject>):void
    {
        var numObjects:int = objects.length;
        _grid = new Vector.<Vector.<DisplayObject>>(_numCells);
        _checks = new Vector.<DisplayObject>();
        // 全てのオブジェクトについてループする
        for (var i:int = 0; i < numObjects; i++)
        {
            var obj:DisplayObject = objects[i];
            // 1次元の格子中の位置を表す配列の添え字を
            // 計算する
            var index:int = Math.floor(obj.y / _gridSize) *
                         _numCols + Math.floor(obj.x / _gridSize);

            // iにオブジェクトがなければ、格子を生成する
            if (_grid[index] == null)
            {
                _grid[index] = new Vector.<DisplayObject>;
            }

            // 格子にオブジェクトを追加する
            _grid[index].push(obj);
        }
        checkGrid();
    }
    
    private function checkGrid():void
    {
        // 各格子をループする
        for (var i:int = 0; i < _numCols; i++)
        {
            for (var j:int = 0; j < _numRows; 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); // 右下
            }
        }
    }    

    private function checkOneCell(x:int, y:int):void
    {
        // (x, y)で表される格子を得る
        var cell:Vector.<DisplayObject> = _grid[y * _numCols + x];
        if (cell == null) return;        

        // 格子中のオブジェクトの個数
        var cellLength:int = cell.length;

        // 全てのオブジェクトを互いに比較する
        for (var i:int = 0; i < cellLength - 1; i++)
        {
            var objA:DisplayObject = cell[i];
            for (var j:int = i + 1; j < cellLength; j++)
            {
                var objB:DisplayObject = cell[j];
                _checks.push(objA, objB);
            }
        }
    }

    
    private function checkTwoCells(x1:int, y1:int,
                                   x2:int, y2:int):void
    {
        // 格子が存在することを確認
        if (x2 >= _numCols || x2 < 0 || y2 >= _numRows) return;

        // 各格子にオブジェクトが存在することを確認
        var cellA:Vector.<DisplayObject> =
                       _grid[y1 * _numCols + x1];

        var cellB:Vector.<DisplayObject> =
                       _grid[y2 * _numCols + x2];

        if (cellA == null || cellB == null) return;
        var cellALength:int = cellA.length;
        var cellBLength:int = cellB.length;

        // 格子中の全てのオブジェクトを他の格子の全ての
        // オブジェクトと比較する
        for (var i:int = 0; i < cellALength; i++)
        {
            var objA:DisplayObject = cellA[i];
            for (var j:int = 0; j < cellBLength; j++)
            {
                var objB:DisplayObject = cellB[j];
                _checks.push(objA, objB);
            }
        }
    }

    public function get checks():Vector.<DisplayObject>
    {
        return _checks;
    }
}