根据世界级flash 大师Keith Peters的网格算法,我们可以将上百个小球的互相碰撞变成现实.
根据个人看法,他这种方法是将大的东西简化成小方块之间的球体检测,通过循环来布满整个stage区域.
本人理解具体的逻辑应该如下,如有不准确,还请各位指正
(1)首先根据屏幕,规定网格大小,然后通过两层循环来布满整个场景.
(2)要求网格的大小最起码要大过DisplayObject的大小,否则会出错
(3)通过数组将小球push到每个网格Array里,然后在在当前网格本身,以及与它相邻的(右,左下,下,右下)4个方
向的格子里push进在格子内的小球,*注意格子是从[0][0]算起的*,具体小球在哪个格里通过
var xpos:int = Math.floor(ball.x / GRID_SIZE);
var ypos:int = Math.floor(ball.y / GRID_SIZE);
即可得到,
(4)最后我们通过检测当前格,以及其他4个相邻的格子之间小球的距离来检测是否碰撞到.代码应该如下
//小球碰撞检测
private function checkCollision(ballA:Ball,ballB:Ball) {
_numChecks++;
trace(_numChecks);
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;
}
}
下面给出没有优化过的代码
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.geom.Rectangle
/**
* ...
* @author spade-A
*/
public class Main 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 = 80;
private var _numChecks:int = 0;
public function Main()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
makeBalls();
makeGrid();
drawGrid();
assignBallsToGrid();
checkGrid();
}
private function makeBalls() {
_balls = new Array();
for (var i:int = 0; i < _numBalls;i++ ) {
var ball:Ball = new Ball(RADIUS/2);
ball.x = Math.random() * stage.stageWidth;
ball.y = Math.random() * stage.stageHeight;
addChild(ball);
_balls.push(ball);
}
}
private function makeGrid() {
_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();
}
}
}
private function drawGrid() {
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);
}
}
private function assignBallsToGrid() {
for (var i:int = 0; i < _numBalls;i++ ) {
var ball:Ball = _balls[i] as Ball;
//球的位置/格子大小,可得所在的行,列
var xpos:int = Math.floor(ball.x / GRID_SIZE);
var ypos:int = Math.floor(ball.y / GRID_SIZE);
_grid[xpos][ypos].push(ball);
}
}
//检测格子
private function checkGrid() {
//i=列,j=行
for (var i:int = 0; i < _grid.length;i++ ) {
for (var j:int = 0; j < _grid[i].length;j++ ) {
checkOneCell(i, j);
checkTowCell(i, j, i + 1, j);//右边
checkTowCell(i, j, i - 1, j + 1);//左下方
checkTowCell(i, j, i, j + 1);//正下方
checkTowCell(i, j, i + 1, j + 1);//右下方
}
}
}
private function checkOneCell(x:int,y:int) {
var cell:Array = _grid[x][y] as Array;
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);
}
}
}
private function checkTowCell(x1:int,y1:int,x2:int,y2:int) {
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;
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);
}
}
}
//小球碰撞检测
private function checkCollision(ballA:Ball,ballB:Ball) {
_numChecks++;
trace(_numChecks);
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;
}
}
}
}
具体优化的代码还请查看作者的代码.