2D Grid (ff ff ff: まるをしきつめる)
forked from forked from: forked from: まるをしきつめる (diff: 183)
ActionScript3 source code
/**
* Copyright Thy ( http://wonderfl.net/user/Thy )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/cBOl
*/
// forked from Thy's forked from: まるをしきつめる
// forked from nemu90kWw's まるをしきつめる
package
{
import flash.display.*;
import flash.events.*;
import flash.geom.Point;
import net.hires.debug.Stats;
public class FlashTest extends Sprite
{
private var
num:int = 150, // how many circles
gridSize:Number = 100, // the circle max width
circles:Vector.<Circle> = new Vector.<Circle>(num, true),
// an grid
grid:Vector.<Vector.<Vector.<Circle>>>;
public function FlashTest()
{
graphics.beginFill(0xD0D0FF);
graphics.drawRect(0, 0, 465, 465);
graphics.endFill();
stage.frameRate = 120;
var i:int = -1;
while(++i < num)
{
circles[i] = new Circle(465/2+Math.random()*100-50,
465/2+Math.random()*100-50,
Math.random()*Math.random()*50);
this.addChild(circles[i]);
}
stage.addEventListener(MouseEvent.CLICK, onClick);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
addChild(new Stats());
}
private function onClick(e:MouseEvent):void
{
A = 0;
var // create circles
i:int = -1,
circle:Circle;
while(++i < num)
{
circle = circles[i];
circle.x = mouseX + Math.random()*100 - 50;
circle.y = mouseY + Math.random()*100 - 50;
}
}
private var A:int;
private function onEnterFrame(e:Event):void
{
trace(++A)
// arranges circles in a 2D grid
gride();
// grid[y][x] = one list of circles
var // variables
i:int = -1, j:int,
k:int, l:int, m:int, n:int, //= num -1,
c1:Circle, c2:Circle,
dx:Number, dy:Number, d:Number,
mx:Number, my:Number,
angle:Number, multiplier:Number, cos:Number, sin:Number;
var // grid stuff
gr:Vector.<Circle>; // list of circles
var
row:int = grid.length, // colums
col:int = grid[0].length; // rows
/* Imagine an 2D grid like:
* 1 2 3
* 4 5 6
* 7 8 9
*
* so, when we're at the circles from grid 1,
* and test circles from this grid each other.
* then, we test circles from grid 1 with
* circles from grid2, 4 and 5.
*
* but, if we are at grid 9, for example, we dont
* need to add any more grids to the collision test.
*/
// the following is and standard collision test
--col; --row;
while (++i < row)
{
// loop, but not for the button corner grid
j = -1;
while (++j < col)
{
// loop, but not for the right corner grid
gr = grid[i][j].concat();
l = gr.length;
gr = gr.concat(grid[i][j + 1], grid[i + 1][j], grid[i + 1][j + 1])
k = -1; n = gr.length;
// so all circles from those list tests collisions each other
while (++k < l)
{
m = k;
while (++m < n)
{
c1 = gr[k];
c2 = gr[m];
dx = c1.x - c2.x;
dy = c1.y - c2.y;
d = Math.sqrt((dx*dx) + (dy*dy));
if(d < c1.size+c2.size)
{
cos = dx / d;
sin = dy / d;
multiplier = (c1.size + c2.size - d) * .5;
c1.x += mx = cos * multiplier;
c1.y += my = sin * multiplier;
c2.x -= mx;
c2.y -= my;
}
}
}
}
}
// with that, in that imaginary grid, we still
// got to test the 'right corner' and the
// 'button corner' grids and the 'right button corner grid'
// lets test the 'button corner'.
// Just a small change from the standard collision test
// ++row; i = row -1;
i = row;
// loop, for the button corner grid only
j = -1;
while (++j < col)
{
// loop, but not for the right corner grid
gr = grid[i][j].concat();
l = gr.length;
gr = gr.concat(grid[i][j + 1])
k = -1; n = gr.length;
// so all circles from those list tests collisions each other
while (++k < l)
{
m = k;
while (++m < n)
{
c1 = gr[k];
c2 = gr[m];
dx = c1.x - c2.x;
dy = c1.y - c2.y;
d = Math.sqrt((dx*dx) + (dy*dy));
if(d < c1.size+c2.size)
{
cos = dx / d;
sin = dy / d;
multiplier = (c1.size + c2.size - d) * .5;
c1.x += mx = cos * multiplier;
c1.y += my = sin * multiplier;
c2.x -= mx;
c2.y -= my;
}
}
}
}
// now, we test the 'right corner' grid
i = -1;
while (++i < row)
{
// ++col, j = col-1;
j = col;
// loop, but not for the button corner grid
gr = grid[i][j].concat();
l = gr.length;
gr = gr.concat(grid[i + 1][j])
k = -1; n = gr.length;
// so all circles from those list tests collisions each other
while (++k < l)
{
m = k;
while (++m < n)
{
c1 = gr[k];
c2 = gr[m];
dx = c1.x - c2.x;
dy = c1.y - c2.y;
d = Math.sqrt((dx*dx) + (dy*dy));
if(d < c1.size+c2.size)
{
cos = dx / d;
sin = dy / d;
multiplier = (c1.size + c2.size - d) * .5;
c1.x += mx = cos * multiplier;
c1.y += my = sin * multiplier;
c2.x -= mx;
c2.y -= my;
}
}
}
}
// finally, the last untested grid is the 'right button'
// ++row; i = row-1; ++col; j = col-1;
i = row; j = col;
gr = grid[i][j];
l = gr.length;
k = -1; n = l;
// so all circles from those list tests collisions each other
while (++k < l)
{
m = k;
while (++m < n)
{
c1 = gr[k];
c2 = gr[m];
dx = c1.x - c2.x;
dy = c1.y - c2.y;
d = Math.sqrt((dx*dx) + (dy*dy));
if(d < c1.size+c2.size)
{
cos = dx / d;
sin = dy / d;
multiplier = (c1.size + c2.size - d) * .5;
c1.x += mx = cos * multiplier;
c1.y += my = sin * multiplier;
c2.x -= mx;
c2.y -= my;
}
}
}
// with this last grid tested, we end our frame!
}
// the grid. inside the drig, we find the circles
private function gride():void
{
var tx:int, ty:int, minX:int, minY:int;
var maxX:int, maxY:int;
var c:Circle = circles[0];
minX = maxX = tx = c.tx = c.x/50;
minY = maxY = ty = c.ty = c.y/50;
// see the circle position (in grids)
var i:int = -1, j:int = 0;
while(++i<num)
{
c = circles[i];
c.tx = tx = c.x / gridSize;
c.ty = ty = c.y / gridSize;
if(tx < minX) minX = tx;
if(tx > maxX) maxX = tx;
if(ty < minY) minY = ty;
if(ty > maxY) maxY = ty;
}
// make the grid
var l1:int = maxY - minY +1, l2:int = maxX - minX +1;
grid = new Vector.<Vector.<Vector.<Circle>>>(l1, true);
i = -1;
while(++i < l1)
{
grid[i] = new Vector.<Vector.<Circle>>(l2, true);
j = -1;
while (++j < l2)
{
grid[i][j] = new Vector.<Circle>();
}
}
// adjust circle position (in grids)
i = -1;
while(++i<num)
{
c = circles[i];
grid[c.ty - minY][c.tx - minX].push(c);
}
}
}
}
import flash.display.*;
class Circle extends Shape
{
public var
size:Number, tx:int, ty:int;
function Circle(x:Number, y:Number, size:Number)
{
this.x = x;
this.y = y;
this.size = size;
graphics.beginFill(0xFFA000);
graphics.lineStyle(2, 0x402000);
graphics.drawCircle(0, 0, size);
graphics.endFill();
this.cacheAsBitmap = true;
}
}