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
/**
* 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);
}
}
}