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

Very simple ball simulation

I learned from here:http://82.30.70.163/BlueThen/wordpress/index.php/processing-app/do-you-like-balls/
Get Adobe Flash player
by heroboy 09 Mar 2011
    Embed
/**
 * Copyright heroboy ( http://wonderfl.net/user/heroboy )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/eKyu
 */

package 
{
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.events.Event;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import net.hires.debug.Stats;
    /**
     * ...
     * @author ywq
     */
    public class Main extends Sprite 
    {
        public var balls:Vector.<Ball> = new Vector.<Ball>();
        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        public function createBalls():void
        {
            var bounds:Rectangle = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
            var x:int,y:int;
            for (y = 0; y < 10;++y )
            {
                for (x = 0; x < 20;++x )
                {
                    balls.push(new Ball(new Point( x*22+20+Math.random()*2,y*22+20 +Math.random()*2), bounds));
                }
            }
        }
        public var pause:Boolean = false;
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            stage.align = StageAlign.TOP_LEFT;
            createBalls();
            addEventListener(Event.ENTER_FRAME, onEnterFrame);
            
            stage.addEventListener("click", function(e:Event):void
            {
                if (pause)
                {
                    addEventListener(Event.ENTER_FRAME, onEnterFrame);
                }
                else
                {
                    removeEventListener(Event.ENTER_FRAME, onEnterFrame);
                }
                pause = !pause;
            });
            addChild(new Stats());
            
        }
        
        private function update(dt:Number):void
        {
            const g:Point = new Point(0, 9.0);
            var b:Ball;
            //add gravity
            for each(b in balls)
            {
                b.applyForce(g);
            }
            for each(b in balls)
            {
                b.update(dt);
            }
            //make collide
            var grids:Vector.<Vector.<Ball>>;// = new Vector.<Vector.<Ball>>();
            var grid_size:Number = 22;
            var cols:int = int(stage.stageWidth / grid_size) + 1;
            var rows:int = int(stage.stageHeight / grid_size) + 1;
            var idx:int;
            grids = new Vector.<Vector.<Ball>>(cols * rows, true);
            for each(b in balls)
            {
                var ix:int = int(Math.ceil(b.position.x / grid_size));
                var iy:int = int(Math.ceil(b.position.y / grid_size));
                if (ix >= 0 && ix < cols &&
                    iy >= 0 && iy < rows)
                {
                    idx = iy * cols + ix;
                    if (grids[idx] == null)
                        grids[idx] = new Vector.<Ball>();
                    grids[idx].push(b);
                }
                else
                {
                    trace("out of bound?");
                }
            }
            var y:int, x:int;
            var drawLine:Boolean = true;
            graphics.lineStyle(1.0, 0x888888, 0.8);
            graphics.beginFill(0xff0000, 1);
            graphics.drawCircle(5, 5, 5);
            graphics.endFill();
            for ( x = 0; x < stage.stageWidth && drawLine; x += grid_size )
            {
                graphics.moveTo(x, 0);
                graphics.lineTo(x, stage.stageHeight);
            }
            for (y = 0; y < stage.stageHeight && drawLine; y += grid_size )
            {
                graphics.moveTo(0, y);
                graphics.lineTo(stage.stageWidth, y);
            }
            for (y = 0; y < rows;++y )
                for (x = 0; x < cols;++x )
                {
                    idx = y * cols + x;
                    var currentGrid:Vector.<Ball> = grids[idx];
                    if (currentGrid == null) continue;
                    
                    var i:int, j:int;
                    for (i = 0; i < currentGrid.length;++i )
                        for (j = i + 1; j < currentGrid.length;++j)
                        {
                            Ball.checkCollide(currentGrid[i], currentGrid[j]);
                            if (drawLine) Ball.drawCollideLine(currentGrid[i], currentGrid[j], graphics);
                        }
                    
                    var idx_right:int = y * cols + x + 1;
                    var idx_bottom:int = (y + 1) * cols + x;
                    var idx_rb:int = (y + 1) * cols + x + 1;
                    var idx_ru:int = (y - 1) * cols + x + 1;
                    if (x + 1 < cols && grids[idx_right] != null)
                    {
                        for (i = 0; i < currentGrid.length;++i )
                            for (j = 0; j < grids[idx_right].length;++j)
                            {
                                Ball.checkCollide(currentGrid[i], grids[idx_right][j]);
                                if (drawLine) Ball.drawCollideLine(currentGrid[i], grids[idx_right][j], graphics);
                            }
                    }
                    
                    if (y + 1 < rows && grids[idx_bottom] != null)
                    {
                        for (i = 0; i < currentGrid.length;++i )
                            for (j = 0; j < grids[idx_bottom].length;++j)
                            {
                                Ball.checkCollide(currentGrid[i], grids[idx_bottom][j]);
                                if (drawLine) Ball.drawCollideLine(currentGrid[i], grids[idx_bottom][j], graphics);
                            }
                    }
                    if (x + 1 < cols && y + 1 < rows && grids[idx_rb] != null)
                    {
                        for (i = 0; i < currentGrid.length;++i )
                            for (j = 0; j < grids[idx_rb].length;++j)
                            {
                                Ball.checkCollide(currentGrid[i], grids[idx_rb][j]);
                                if (drawLine) Ball.drawCollideLine(currentGrid[i], grids[idx_rb][j], graphics);
                            }
                    }
                    if (x + 1<cols&& y-1>=0 && grids[idx_ru]!=null)
                    {
                        for (i = 0; i < currentGrid.length;++i )
                            for (j = 0; j < grids[idx_ru].length;++j)
                            {
                                Ball.checkCollide(currentGrid[i], grids[idx_ru][j]);
                                if (drawLine) Ball.drawCollideLine(currentGrid[i], grids[idx_ru][j], graphics);
                            }
                    }
                }
            for each(b in balls)
            {
                b.checkBound(b.position,true);
            }

        }
        
        private function onEnterFrame(e:Event):void
        {
            var dt:Number = 0.1;
            graphics.clear();
            update(dt);
            var b:Ball;
            for each(b in balls)
            {
                b.draw(graphics);
            }
        }
    }
    
}

    import flash.display.Graphics;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    /**
     * ...
     * @author ywq
     */
    class Ball 
    {
        public static const restitution:Number = 1;
        public var mass:Number = 1.0;
        public var imass:Number = 1 / mass;
        public var position:Point = new Point();
        public var lastPosition:Point = new Point();
        public var force:Point = new Point();
        public var radius:Number = 10;
        public var v:Point = new Point();
        public var bounds:Rectangle;
        public var lastdt:Number = 0.01;
        public function Ball(pos:Point,bounds:Rectangle) 
        {
            this.position = pos.clone();
            this.lastPosition = pos.clone();
            this.bounds = bounds;
        }
        
        public function applyForce(f:Point):void
        {
            //force.offset(f.x, f.y);
            force = force.add(f);
        }
        public function update(dt:Number):void
        {
            lastdt = dt;
            var newPosition:Point = position.clone();
            var acc:Point = force.clone();
            acc.x *= imass;
            acc.y *= imass;
            newPosition.x += (position.x - lastPosition.x) + 0.5 * acc.x * dt * dt;
            newPosition.y += (position.y - lastPosition.y) + 0.5 * acc.y * dt * dt;
            
            //
            lastPosition = position;
            position = newPosition;
            v.x = (position.x - lastPosition.x)/dt;
            v.y = (position.y - lastPosition.y)/dt;
            //
            force.x = force.y = 0;
            //bound(position, true);
        }
        public function checkBound(position:Point,needApplyForce:Boolean):void
        {
            var force:Point = new Point;
            if (position.x < bounds.left + radius)
            {
                force.x = bounds.left + radius - position.x;
                position.x = bounds.left + radius;
            }
            else if (position.x > bounds.right - radius)
            {
                force.x = bounds.right - radius - position.x;
                position.x = bounds.right - radius;
            }
            if (position.y < bounds.top + radius)
            {
                force.y = bounds.top + radius - position.y;
                position.y = bounds.top + radius;
            }
            else if (position.y > bounds.bottom - radius)
            {
                force.y = bounds.bottom - radius - position.y;
                position.y = bounds.bottom - radius;
            }
            if (needApplyForce)
            {
                var forceNormal:Point = force.clone();
                forceNormal.normalize(1.0);
                var vn:Number = v.x * forceNormal.x + v.y * forceNormal.y;
                if (vn >= 0) return;
                var i:Number = -(1 + restitution) * vn / (imass);
                force.normalize(1.0);
                force.x *= i;
                force.y *= i;
                applyForce(force);
            }
        }
        public function draw(g:Graphics):void
        {
            g.lineStyle(1.0, 0xff0000);
            g.drawCircle(position.x, position.y, radius);
        }
        public function drawForce(g:Graphics):void
        {
            g.lineStyle(1.0, 0x00ff00);
            g.moveTo(position.x, position.y);
            g.lineTo(position.x + force.x, position.y + force.y);
        }
        public static function drawCollideLine(b1:Ball, b2:Ball,g:Graphics):void
        {
            g.lineStyle(1.0, 0x00ff00, 0.8);
            g.moveTo(b1.position.x, b1.position.y);
            g.lineTo(b2.position.x, b2.position.y);
        }
        public static function checkCollide(b1:Ball, b2:Ball):void
        {
            if (b1 === b2) return;
            var delta:Point = b1.position.subtract(b2.position);
            var dist2:Number = delta.x * delta.x + delta.y * delta.y;
            var rr:Number = b1.radius + b2.radius;
            if (dist2 >= rr * rr)
                return;
            var dist:Number = Math.sqrt(dist2);
            if (dist == 0) dist = rr - 1;
            var mtd:Point = delta.clone();
            var _mm:Number = (rr - dist) / dist;
            mtd.x *= _mm;
            mtd.y *= _mm;
            //move
            var im1:Number = b1.imass / (b1.imass + b2.imass);
            var im2:Number = b2.imass / (b1.imass + b2.imass);
            b1.position.x += im1 * mtd.x;
            b1.position.y += im1 * mtd.y;
            b2.position.x -= im2 * mtd.x;
            b2.position.y -= im2 * mtd.y;
         
            
            //fix velocity
            var v:Point = b1.v.subtract(b2.v);
            var mtdNormal:Point = mtd.clone();
            mtdNormal.normalize(1.0);
            var vn:Number = v.x * mtdNormal.x + v.y * mtdNormal.y;
            if (vn > 0) return;
            
            var i:Number = -(1 + restitution) * vn / (b1.imass + b2.imass);
            var impulse:Point = mtdNormal.clone();
            impulse.x *= i;
            impulse.y *= i;
            b1.applyForce(impulse);
            impulse.x = -impulse.x;
            impulse.y = -impulse.y;
            b2.applyForce(impulse);
        }
    }