2D Grid (ff ff ff: まるをしきつめる)

by Thy forked from forked from: forked from: まるをしきつめる (diff: 183)
♥1 | Line 240 | Modified 2011-02-14 12:19:59 | MIT License
play

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;
    }
}