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

Ball Drop

package {
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	

	[SWF(backgroundColor="#999999")]
	public class QuickPhysics extends Sprite
	{
		
		private static const NUM_CIRCLES:int = 7;
		
		private var circles:Vector.<Circle>;
		private var lines:Vector.<Line>;
		
		private var simulator:Physics;
		private var renderer:Renderer;
		
		public function QuickPhysics()
		{
			
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.frameRate = 40;
			
			circles = new Vector.<Circle>();
			
			while( circles.length <= NUM_CIRCLES )
			{
				var circle:Circle = new Circle( 10 + Math.random() * 40, 1, Math.random(), Math.random() );
				circle.x = 20 + Math.random() * 400;
				circles.push( circle );
			}
			
			lines = Vector.<Line>( [ 
										new Line( 0, 0, 300, 70 ),
										new Line( 450, 0, 450, 100 ),
										new Line( 450, 100, 150, 300 ),
										new Line( -50, 200, 10, 400 ),
										new Line( 10, 400, 100, 500 )
										
									 ] );
			
			simulator = new Physics();
			renderer = new Renderer();
			
			renderer.graphics = graphics;
			
			addEventListener( Event.ENTER_FRAME, onEnterFrame );
			
		}
		
		private function onEnterFrame( event:Event ) : void
		{
			simulator.step( 1 / stage.frameRate, circles, lines );
			renderer.render( circles, lines );
		}
		
	}
}

import __AS3__.vec.Vector;
import flash.display.*;
import flash.geom.Point;
	

const G:Number = 9.81 * 40; //pixel per meter ratio
const EPSILON:Number = 1.5;


class Element
{
	
	public var coeffRest:Number;
	public var coeffFric:Number;
	
	public function Element( coeffRest:Number = 0.5, coeffFric:Number = 0.5 )
	{
		this.coeffRest = coeffRest;
		this.coeffFric = coeffFric;
	}
	
}

class Line extends Element
{
	
	public var ax:Number, ay:Number, bx:Number, by:Number;
	
	public function Line( ax:Number, ay:Number, bx:Number, by:Number, coeffRest:Number = 0.5, coeffFric:Number = 0.5 ) 
	{
		
		super( coeffRest, coeffFric );
		
		this.ax = ax;
		this.ay = ay;
		this.bx = bx;
		this.by = by;
		
	}
	
}

class Circle extends Element
{
	
	public var radius:Number;
	
	public var x:Number = 0;
	public var y:Number = 0;
	
	public var vx:Number = 0;
	public var vy:Number = 0;
	
	public var theta:Number = 0;
	public var av:Number = 0;
	
	public var mass:Number;
	public var inertiaTensor:Number;
	
	public function Circle( radius:Number = 10, density:Number = 1.0, coeffRest:Number = 0.5, coeffFric:Number = 0.5 )
	{
		
		super( coeffRest, coeffFric );
		
		this.radius = radius;
		this.density = density;
		
	}
	
	public function set density( value:Number ) : void
	{
		
		var area:Number = Math.PI * radius * radius;
		
		mass = value * area;
		inertiaTensor = ( 2 / 5 ) * mass * radius * radius;
		
	}
	
	public function update( dt:Number ) : void
	{
		
		vy += G * dt;
		
		x += vx * dt;
		y += vy * dt;
		
		theta += av * dt;
		
	}
	
}

class Renderer
{
	
	public static const HEX:uint = 0xFFFFFF;
	
	public var graphics:Graphics;
	
	public function render( circles:Vector.<Circle>, lines:Vector.<Line> ) : void
	{
		
		graphics.clear();
		graphics.lineStyle( 1, HEX );
		
		for each( var circle:Circle in circles )
		{
			renderCircle( circle );
		}
		
		for each( var line:Line in lines )
		{
			renderLine( line );
		}
		
	}
	
	public function renderCircle( circle:Circle ) : void
	{
		graphics.drawCircle( circle.x, circle.y, circle.radius );
		graphics.moveTo( circle.x, circle.y );
		graphics.lineTo( circle.x + Math.cos( circle.theta ) * circle.radius, circle.y + Math.sin( circle.theta ) * circle.radius );
	}
	
	public function renderLine( line:Line ) : void
	{
		graphics.moveTo( line.ax, line.ay );
		graphics.lineTo( line.bx, line.by );
	}
	
}


class Physics
{
	
	public function step( dt:Number, circles:Vector.<Circle>, lines:Vector.<Line> ) : void
	{
		
		for each( var circle:Circle in circles )
		{
			circle.update( dt );
		}
		
		resolveCollisions( circles, lines );
		
	}
	
	private function resolveCollisions( circles:Vector.<Circle>, lines:Vector.<Line> ) : void
	{
		
		var ioP:Point = new Point();
		var ioN:Point = new Point();
		
		for each( var circle:Circle in circles )
		{
			for each( var line:Line in lines )
			{
				if( areColliding( circle, line, ioP, ioN ) )
				{
					resolveCollision( circle, line, ioP.x, ioP.y, ioN.x, ioN.y );
				}
			}
			
			wrap( circle );
			
		}
		
	}
	
	private function wrap( circle:Circle ) : void
	{
		if( circle.y > 500 )
		{
			circle.y = -40;
			circle.x = 20 + Math.random() * 400;
			circle.vx = circle.vy = circle.av = 0;
		}
	}
	
	private function areColliding( circle:Circle, line:Line, ioP:Point, ioN:Point ) : Boolean
	{
		
		var abx:Number = line.bx - line.ax;
		var aby:Number = line.by - line.ay;
		
		var acx:Number = circle.x - line.ax;
		var acy:Number = circle.y - line.ay;
		
		var ACDotAB:Number = acx * abx + acy * aby;
		var t:Number = ACDotAB / ( abx * abx + aby * aby );
		
		if( t < 0 ) t = 0;
		else if( t > 1 ) t = 1;
		
		var cpx:Number = line.ax + abx * t;
		var cpy:Number = line.ay + aby * t;
		
		var cnx:Number = circle.x - cpx;
		var cny:Number = circle.y - cpy;
		
		if( cnx * cnx + cny * cny <= circle.radius * circle.radius )
		{
			
			ioP.x = cpx;
			ioP.y = cpy;
			ioN.x = cnx;
			ioN.y = cny;
			
			return true;
			
		}
		
		return false;
		
	}
	
	private function resolveCollision( circle:Circle, line:Line, px:Number, py:Number, nx:Number, ny:Number ) : void
	{
		
		var cibx:Number = -nx;
		var ciby:Number = -ny;
		
		var length:Number = Math.sqrt( cibx * cibx + ciby * ciby );
		
		nx /= length;
		ny /= length;
		
		var diff:Number = circle.radius - length;
		
		circle.x += nx * diff;
		circle.y += ny * diff;
		
		var perpX:Number = -ciby;
		var perpY:Number = cibx;
		
		var perpDotNorm:Number = perpX * nx + perpY * ny;
		
		var denom:Number = nx * ( nx / circle.mass ) + ny * ( ny / circle.mass );
		denom += ( perpDotNorm * perpDotNorm ) / circle.inertiaTensor;
		
		var rvx:Number = circle.vx + perpX * circle.av;
		var rvy:Number = circle.vy + perpY * circle.av;
		
		var rvNorm:Number = rvx * nx + rvy * ny;
		
		var coeffRest:Number = rvNorm > -EPSILON ? 0 : ( line.coeffRest + circle.coeffRest ) * 0.5;
		
		var impulse:Number = ( -( 1 + coeffRest ) * rvNorm ) / denom;
		
		var dx:Number = nx * ( impulse / circle.mass );
		var dy:Number = ny * ( impulse / circle.mass );
		
		var dq:Number = ( perpX * nx * impulse + perpY * ny * impulse ) / circle.inertiaTensor;
		
		var tangX:Number = -ny;
		var tangY:Number = nx;
		
		var cpTang:Number = perpX * tangX + perpY * tangY;
		
		denom = tangX * ( tangX / circle.mass ) + tangY * ( tangY / circle.mass );
		denom += ( cpTang * cpTang ) / circle.inertiaTensor;
		
		var rvTang:Number = rvx * tangX + rvy * tangY;
		
		impulse = -rvTang / denom * ( circle.coeffFric + line.coeffFric ) * 0.5;
		
		dx += tangX * ( impulse / circle.mass );
		dy += tangY * ( impulse / circle.mass );
		
		dq += ( perpX * tangX * impulse + perpY * tangY * impulse ) / circle.inertiaTensor;
		
		circle.vx += dx;
		circle.vy += dy;
		
		circle.av += dq;
		
	}
	
}