forked from: flash on 2010-7-3
forked from flash on 2010-7-3 (diff: 273)
衝突判定 「詳解 ActionScript 3.0 アニメーション」より 写経であーる。
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/3mKn
*/
// forked from fakestar0826's flash on 2010-7-3
//衝突判定
//「詳解 ActionScript 3.0 アニメーション」より
//写経であーる。
package {
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.text.TextField;
import flash.utils.getTimer;
import flash.display.DisplayObject;
public class FlashTest extends Sprite {
private const GRID_SIZE:Number = 50;
private const RADIUS:Number = 25;
private var _balls:Vector.<DisplayObject>;
private var _grid:CollisionGrid;
private var _numBalls:int = 100;
private var _numChecks:int = 0;
public function FlashTest() {
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
_grid = new CollisionGrid(stage.stageWidth, stage.stageHeight, GRID_SIZE);
_grid.drawGrid(graphics);
makeBalls();
var startTime:int;
var elapsed:int;
var i:int;
startTime = getTimer();
for(i = 0;i < 10;i++)
{
_grid.check(_balls);
var numChecks:int = _grid.checks.length;
for(var j:int = 0;j < numChecks; j += 2)
{
checkCollision(_grid.checks[j] as Ball, _grid.checks[j + 1] as Ball);
}
}
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);
}
public function makeBalls():void
{
_balls = new Vector.<DisplayObject>(_numBalls);
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;
ball.vx = Math.random() * 4 - 2;
ball.vy = Math.random() * 4 - 2;
addChild(ball);
_balls[i] = ball;
}
}
public function checkCollision(ballA:Ball, ballB:Ball):void
{
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;
}
}
}
}
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;
}
}
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, 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];
var index:int = Math.floor(obj.y / _gridSize) * _numCols + Math.floor(obj.x / _gridSize);
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);
checkTwoCell(i, j, i + 1, j);
checkTwoCell(i, j, i - 1, j + 1);
checkTwoCell(i, j, i, j + 1);
checkTwoCell(i, j, i + 1, j + 1);
}
}
}
private function checkOneCell(x:int, y:int):void
{
var cell:Vector.<DisplayObject> = _grid[y * _numCols + x];
if (cell == null) return;
var cellLength:int = cell.length;
for (var i:int; i < cellLength; 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 checkTwoCell(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;
}
}
