forked from: elastic collisions
forked from elastic collisions (diff: 1)
ActionScript3 source code
/**
* Copyright I.lay.Ayan ( http://wonderfl.net/user/I.lay.Ayan )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/w4pb
*/
// forked from lukevanin's elastic collisions
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 = 2;
area = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
minVelocity = 1.0;
maxVelocity = 3.5;
backgroundColor = 0x000000;
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(10);
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 collideMoving(pA:Point, vA:Point, pB:Point, vB:Point):void
{
// excerpt from http://www.gamasutra.com/view/feature/3015/pool_hall_lessons_fast_accurate_.php?page=3
// First, find the normalized vector n from the center of
// circle1 to the center of circle2
var normal:Point = pA.subtract(pB);
normal.normalize(1);
// Find the length of the component of each of the movement
// vectors along n.
// a1 = v1 . n
// a2 = v2 . n
var tA:Number = dotproduct(vA, normal);
var tB:Number = dotproduct(vB, normal);
// Using the optimized version,
// optimizedP = 2(a1 - a2)
// -----------
// m1 + m2
var optimizedP:Number = (2.0 * (tA - tB)) / 2;
// Calculate v1', the new movement vector of circle1
// v1' = v1 - optimizedP * m2 * n
vA.x = vA.x - (optimizedP * normal.x);
vA.y = vA.y - (optimizedP * normal.y);
// Calculate v1', the new movement vector of circle1
// v2' = v2 + optimizedP * m1 * n
vB.x = vB.x + (optimizedP * normal.x);
vB.y = vB.y + (optimizedP * normal.y);
}
private function dotproduct(a:Point, b:Point):Number
{
return (a.x * b.x) + (a.y * b.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);
}
}
}
