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

simple elastic collisions

A simple particle system to illustrate basic point elastic collisions. In response to a question at http://gamedev.stackexchange.com/posts/15915/edit
Get Adobe Flash player
by lukevanin 13 Aug 2011
/**
 * Copyright lukevanin ( http://wonderfl.net/user/lukevanin )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/jeF1
 */

package 
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.LineScaleMode;
    import flash.display.PixelSnapping;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.ColorTransform;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.utils.Dictionary;
    
    /**
     * ...
     * @author Luke Van In
     */
    public class Main extends Sprite 
    {
        private var positions:Vector.<Point>;
        private var velocities:Vector.<Point>;
        private var sprites:Vector.<Sprite>;
        private var radius:Number;
        private var area:Rectangle;
        private var minVelocity:Number;
        private var maxVelocity:Number;
        private var backgroundColor:uint;
        private var colors:Vector.<uint>;
        private var canvas:Sprite;
        private var buffer:BitmapData;
        private var output:BitmapData;
        private var bitmap:Bitmap;
        
        
        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            radius = 3; 
            area = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
            minVelocity = 1.0;
            maxVelocity = 1.5;
            backgroundColor = 0x333333;
            colors = new <uint>[0x0099FF, 0xFF9900, 0x00FF99, 0x99FF00, 0x9900FF, 0xFF0099];
            canvas = new Sprite();
            buffer = new BitmapData(area.width, area.height, false, backgroundColor);
            output = new BitmapData(area.width, area.height, false, backgroundColor);
            bitmap = new Bitmap(output, PixelSnapping.NEVER, false);
            createParticles(20);
            drawArea();
            addChild(bitmap);
            addEventListener(Event.ENTER_FRAME, frameHandler);
        }
        
        private function drawArea():void
        {
            graphics.beginFill(backgroundColor, 1.0);
            graphics.drawRect(area.x, area.y, area.width, area.height);
            graphics.endFill();
        }
        
        private function createParticles(count:uint):void
        {
            velocities = new Vector.<Point>(count, true);
            positions = new Vector.<Point>(count, true);
            sprites = new Vector.<Sprite>(count, true);
            
            for (var i:int = 0; i < count; i++) {
                var color:uint = colors[i % colors.length ];
                sprites[i] = createSprite(color);
                positions[i] = createNonIntersectingPosition();
                velocities[i] = createVelocity();
            }
        }
        
        private function createSprite(color:uint):Sprite
        {
            var r:Number = radius + 1;
            var output:Sprite = new Sprite();
            output.graphics.beginFill(color, 1.0);
            output.graphics.drawCircle(0, 0, radius);
            output.graphics.endFill();
            canvas.addChild(output);
            return output;
        }
        
        private function createNonIntersectingPosition():Point
        {
            var p:Point = createPosition();
            
            while (hasCollision(p))
                p = createPosition();
                
            return p;
        }
        
        private function hasCollision(a:Point):Boolean
        {
            var r:Number = radius * 2;
            
            for (var i:int = 0, count:int = positions.length; i < count; i++) {
                var b:Point = positions[i];
                
                if (b != null) {
                    if (distance(a, b) < r)
                        return true;
                }
            }
            
            return false;
        }
        
        private function createPosition():Point
        {
            var x:Number = area.x + radius;
            var y:Number = area.y + radius;
            var w:Number = area.width - (radius * 2);
            var h:Number = area.height - (radius * 2);
            var output:Point = new Point();
            output.x = x + (Math.random() * w);
            output.y = y + (Math.random() * h);
            return output;
        }
        
        private function createVelocity():Point
        {
            var f:Number = Math.random() * Math.PI * 2;
            var d:Number = maxVelocity - minVelocity;
            var s:Number = minVelocity + (Math.random() * d);
            var output:Point = new Point();
            output.x = Math.cos(f) * s;
            output.y = Math.sin(f) * s;
            return output;
        }
        
        private function frameHandler(event:Event):void
        {
            checkCollisions();
            updatePositions();
            updateSprites();
            blit();
        }
        
        private function checkCollisions():void
        {
            var r:Number = (radius * 2); 
            var a:Point;
            var b:Point;
            var boundary:Rectangle = new Rectangle(area.x - radius, area.y - radius, area.width + r, area.height + r);
            var count:int = positions.length;
            var d:Number;
            
            for (var i:int = 0; i < count; i++) {
                a = positions[i];
                wrapBoundary(a, boundary)

                for (var j:int = 0; j < i; j++) {
                    b = positions[j];
                    d = distance(a, b);
                    if (d < r) 
                        collideMoving(a, velocities[i], b, velocities[j]);
                }
            }
        }
        
        private function wrapBoundary(p:Point, boundary:Rectangle):void
        {
            if (p.x < boundary.left)
                p.x = boundary.right;
                
            if (p.x > boundary.right)
                p.x = boundary.left;
                
            if (p.y < boundary.top)
                p.y = boundary.bottom;
                
            if (p.y > boundary.bottom)
                p.y = boundary.top;
        }
        
        private function distance(a:Point, b:Point):Number
        {
            var dx:Number = b.x - a.x;
            var dy:Number = b.y - a.y;
            return Math.sqrt((dx * dx) + (dy * dy));
        }
        
        private function collideStatic(p:Point, v:Point):void 
        {
            v.x = -v.x;
            v.y = -v.y;
            p.x += v.x;
            p.y += v.y;
        }
        
        private function collideMoving(pA:Point, vA:Point, pB:Point, vB:Point):void
        {
            var nA:Point = vA.add(vB).subtract(vA);
            var nB:Point = vB.add(vA).subtract(vB);
            
            vA.x = nA.x;
            vA.y = nA.y;
            vB.x = nB.x;
            vB.y = nB.y;
        }
        
        private function updatePositions():void
        {
            var p:Point;
            var v:Point;
            for (var i:int = 0, count:int = velocities.length; i < count; i++) {
                p = positions[i];
                v = velocities[i];
                p.x += v.x;
                p.y += v.y;
            }
        }
        
        private function updateSprites():void
        {
            var sprite:Sprite;
            var p:Point;
            for (var i:int = 0, count:int = positions.length; i < count; i++) {
                p = positions[i];
                sprite = sprites[i];
                sprite.x = p.x;
                sprite.y = p.y;
            }
        }
        
        private function blit():void
        {
            var r:Rectangle = new Rectangle(0, 0, area.width, area.height);
            var p:Point = new Point();
            var m:Matrix = new Matrix();
            var t:ColorTransform = new ColorTransform(1, 1, 1, 0.99, 0, 0, 0, 0);
            output.copyPixels(buffer, r, p);
            output.draw(canvas, m, null, null, r);
            buffer.fillRect(r, backgroundColor);
            buffer.draw(output, m, t, null, r);
        }
    }
    
}