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

Spatial Partitioning Test

Testing internal spacial partitioning object grid class.

Click to add blob.

[+] and [-] to change mouse radius.
Get Adobe Flash player
by abeall 28 Jun 2013
/**
 * Copyright abeall ( http://wonderfl.net/user/abeall )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/5Eya
 */

package  {
    import flash.display.StageScaleMode;
    import flash.display.StageAlign;
    
    import flash.display.MovieClip;
    import flash.display.Shape;
    import flash.events.MouseEvent;
    import flash.utils.Dictionary;
    import flash.geom.Point;
    import flash.events.Event;
    import flash.display.Graphics;
    import flash.display.DisplayObject;
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;
    import flash.display.Sprite;
    
    
    public class SpatialManager extends MovieClip {
       
        private const blobMinRadius:Number = 5;
        private const blobMaxRadius:Number = 15;
        private const blobMaxSpeed:Number = 1;
        private const blobConnectionSensitivity:Number = 4;
        
        private var blobs:Vector.<Shape> = new Vector.<Shape>();
        private var blobsInfo:Dictionary = new Dictionary(true);
        
        private var gridWidth:Number;
        private var gridHeight:Number;
        private var grid:ObjectGrid;
        
        private var gridLayer:Shape;
        private var connectorsLayer:Shape;
        private var mouseLayer:Shape;
        private var blobsLayer:Sprite;
        
        private var mouseRadius:Number = blobMaxRadius;
        
        private var playing:Boolean = true;
        
        public function SpatialManager() {
            
            // init stage
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            
            // init grid
            gridLayer = new Shape();
            gridLayer.cacheAsBitmap = true;
            addChild(gridLayer);
            
            // create the grid layer
            gridLayer = new Shape();
            gridLayer.cacheAsBitmap = true;
            addChild(gridLayer);

            // create the blobs container
            blobsLayer = new Sprite();
            addChild(blobsLayer);
            
            // create connector canvas
            connectorsLayer = new Shape();
            addChild(connectorsLayer);
            
            // create mouse canvas
            mouseLayer = new Shape();
            addChild(mouseLayer);
            
            // draw the grid
            updateGrid();
            
            // add random blobs
            var i:int = 25;
            while(i--)
                addBlob(Math.random() * gridWidth, Math.random() * gridHeight);
            
            stage.addEventListener(MouseEvent.CLICK, stageClick);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, stageKeyDown);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, stageMouseMove);
            stage.addEventListener(MouseEvent.MOUSE_WHEEL, stageMouseWheel);
            stage.addEventListener(Event.RESIZE, stageResize);
            addEventListener(Event.ENTER_FRAME, update);
        }
        
        private function updateGrid():void {
            // grid props
            gridWidth = stage.stageWidth;
            gridHeight = stage.stageHeight;
            
            // build grid
            var cellSize:Number = blobMaxRadius * blobConnectionSensitivity;
            grid = new ObjectGrid(cellSize, gridWidth, gridHeight);
            
            // add existing blobs
            var i:int = blobsLayer.numChildren;
            while(i--){
                grid.add(blobsLayer.getChildAt(i));
            }
            
            // draw grid lines
            var g:Graphics = gridLayer.graphics;
            g.clear();
            g.lineStyle(1, 0xeeeeee);
            for(var w:int = 0; w < gridWidth; w += cellSize){
                g.moveTo(w, 0);
                g.lineTo(w, gridHeight);
                for(var h:int = 0; h < gridHeight; h += cellSize){
                    g.moveTo(0, h);
                    g.lineTo(gridWidth, h);
                }
            }
        }
        
        private function stageClick(e:MouseEvent):void {
            addBlob(stage.mouseX, stage.mouseY);
        }
        
        private function stageKeyDown(e:KeyboardEvent):void {
            switch(e.keyCode){
                case Keyboard.SPACE:
                    playing = !playing;
                    if(playing)
                        addEventListener(Event.ENTER_FRAME, update);
                    else
                        removeEventListener(Event.ENTER_FRAME, update);
                    break;
                case Keyboard.NUMPAD_ADD:
                case Keyboard.EQUAL:
                    mouseRadius++;
                    break;
                case Keyboard.NUMPAD_SUBTRACT:
                case Keyboard.MINUS:
                    mouseRadius--;
                    break;
            }
        }
        
       private function stageMouseMove(e:MouseEvent):void {
            var xPos:Number = stage.mouseX, yPos:Number = stage.mouseY;
           
            var g:Graphics = mouseLayer.graphics;
            g.clear();
            
            g.beginFill(0xff0000);
            g.drawCircle(xPos, yPos, mouseRadius);
            g.endFill();
            
            g.lineStyle(1, 0xff0000, .2);
            var objs:Vector.<DisplayObject> = grid.getObjectsInCircle(xPos, yPos, mouseRadius * blobConnectionSensitivity, g);
            g.lineStyle(3, 0xff0000);
            for each(var obj:DisplayObject in objs){
                g.moveTo(xPos, yPos);
                g.lineTo(obj.x, obj.y);
            }
            
            g.lineStyle(1, 0xff0000);
            g.drawCircle(xPos, yPos, mouseRadius * blobConnectionSensitivity);
        }
        
        private function stageMouseWheel(e:MouseEvent):void {
            mouseRadius += e.delta > 0 ? 1 : -1;
            mouseRadius = Math.abs(mouseRadius);
        }
        
        private function stageResize(e:Event):void {
            updateGrid();
        }
        
        private function update(e:Event):void {
            
            // clear canvas
            var g:Graphics = connectorsLayer.graphics;
            g.clear();
            
            // update grid
            grid.update();
            
            // update blobs
            for each(var blob:Shape in blobs){
                var info:Object = blobsInfo[blob];
                
                // move
                var vector:Point = info.vector;
                blob.x += vector.x;
                blob.y += vector.y;
                
                // bounce off edges
                if(blob.x < 0 || blob.x > gridWidth)
                    vector.x *= -1;
                if(blob.y < 0 || blob.y > gridHeight)
                    vector.y *= -1;
                
                // draw connections
                var nearbyBlobs:Vector.<DisplayObject> = grid.getObjectsInCircle(blob.x, blob.y, info.radius * blobConnectionSensitivity);
                //var nearbyBlobs:Vector.<DisplayObject> = grid.getObjects(blob.x, blob.y);
                if(nearbyBlobs.length > 1){
                    blob.alpha = .5;
                    g.lineStyle(info.radius * 2, info.color, .33);
                    for each(var nearbyBlob:Shape in nearbyBlobs){
                        g.moveTo(blob.x, blob.y);
                        g.lineTo(nearbyBlob.x, nearbyBlob.y);
                    }
                }else{
                    blob.alpha = 1.0;
                }
            }
            
            stageMouseMove(null);
        }
        
        private function addBlob(x:Number, y:Number):void {
            var color:uint = 0xffffff * Math.random();
            var radius:Number = blobMinRadius + (blobMaxRadius - blobMinRadius) * Math.random();
            
            var blob:Shape = new Shape();
            blob.graphics.beginFill(color);
            blob.graphics.drawCircle(0, 0, radius);
            blob.graphics.endFill();
            blob.graphics.lineStyle(1, color, .5);
            blob.graphics.drawCircle(0, 0, radius * blobConnectionSensitivity);
            blob.x = x;
            blob.y = y;
            blobsLayer.addChild(blob);
            blobs.push(blob);
            
            blobsInfo[blob] = {
                color: color,
                radius: radius,
                vector: new Point(
                    -blobMaxSpeed + Math.random() * (blobMaxSpeed * 2), 
                    -blobMaxSpeed + Math.random() * (blobMaxSpeed * 2)
                )
            }
            
            grid.add(blob);
        }
    }
    
}
import flash.display.DisplayObject;
import flash.utils.Dictionary;
import flash.display.Graphics;

internal class ObjectGrid {

    private var cellSize:Number;
    private var numColumns:int;
    private var numRows:int;
    private var numCells:int;
    private var grid:Vector.<Vector.<DisplayObject>>;
    
    private var objects:Vector.<DisplayObject> = new Vector.<DisplayObject>();
    private var objectsLookup:Dictionary = new Dictionary(true);
    
    public function ObjectGrid(cellSize:Number, width:Number, height:Number, objects:Vector.<DisplayObject> = null) {
        this.cellSize = cellSize;
        if(objects)
            this.objects = objects;
        
        // init grid
        numColumns = Math.ceil(width / cellSize) + 1;
        numRows = Math.ceil(height / cellSize) + 1;
        numCells = numColumns * numRows;
        grid = new Vector.<Vector.<DisplayObject>>(numCells, true);
        for(var i:uint = 0; i < numCells; i++) {
            grid[i] = new Vector.<DisplayObject>();
        }
    }
    
    public function add(object:DisplayObject):void {
        if(objectsLookup[object] == null){
            objectsLookup[object] = objects.push(object);
        }
    }
    
    public function remove(object:DisplayObject):void {
        if(objectsLookup[object] != null){
            objects.splice(objectsLookup[object], 1);
            delete objectsLookup[object];
        }
    }
    
    public function update():void {
        // reset grid
        for (var i:uint = 0; i < numCells; ++i) {
            grid[i].length = 0;
        }
        
        // localize all the objects in the grid
        var cellRatio:Number = 1 / cellSize;
        i = objects.length;
        while(i--){
            var obj:DisplayObject = objects[i];
            var cellIndex:uint = int(obj.x * cellRatio) * numRows + (obj.y * cellRatio);
            grid[cellIndex].push(obj);
        }
    }
    
    public function getObjects(x:Number, y:Number, cellRadius:uint = 1, debugLayer:Graphics = null):Vector.<DisplayObject> {
        var xPos:uint = x / cellSize;
        var yPos:uint = y / cellSize;
        
        var xMin:int = xPos - cellRadius;
        if (xMin < 0) xMin = 0;
        
        var yMin:int = yPos - cellRadius;
        if (yMin < 0) yMin = 0;
        
        var xMax:uint = xPos + cellRadius;
        if (xMax >= numColumns) xMax = numColumns - 1;
        
        var yMax:uint = yPos + cellRadius;
        if (yMax >= numRows) yMax = numRows - 1;
        
        var results:Vector.<DisplayObject> = new Vector.<DisplayObject>();
        for (var currX:uint = xMin; currX <= xMax; currX++) {
            var rowIndex:uint = currX * numRows;
            for (var currY:uint = yMin; currY <= yMax; currY++) {
                var objs:Vector.<DisplayObject> = grid[rowIndex + currY];
                for each(var obj:DisplayObject in objs){
                    results.push(obj);
                }
                if(debugLayer){
                    debugLayer.drawRect(currX * cellSize, currY * cellSize, cellSize, cellSize);
                }
            }
        }
        
        return results;
    }
    
    public function getObjectsInCircle(x:Number, y:Number, radius:Number, debugLayer:Graphics = null):Vector.<DisplayObject> {
        var cellRadius:uint = (radius / cellSize) + 1;
        var objs:Vector.<DisplayObject> = getObjects(x, y, cellRadius, debugLayer);
        var squaredRadius:Number = radius * radius;
        var i:int = objs.length;
        while(i--){
            var obj:DisplayObject = objs[i];
            var dist:Number = (obj.x - x) * (obj.x - x) + (obj.y - y) * (obj.y - y);
            if(dist > squaredRadius)
                objs.splice(i, 1);
        }
        return objs;
    }
}