200 small circles
...
@author Thi
/**
* Copyright Thy ( http://wonderfl.net/user/Thy )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/ZvEQ
*/
// forked from http://www.emanueleferonato.com/2008/06/07/managing-multiple-balls-collisions-with-flash-as3-version/
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.StageQuality;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.ColorTransform;
import flash.geom.Point;
import flash.geom.Rectangle;
/**
* ...
* @author Thi
*/
public class Main extends Sprite
{
// drawing
public var circle_shape:Shape
public var circle_data:BitmapData
// buiding or viewing
private var building:Boolean
// circle list
private var num_circles:uint = 200
private var circles:Vector.<Circle> = new Vector.<Circle>(num_circles, true)
// continers
private var num_conteiner:uint = 64
private var conteiners:Vector.<Conteiner> = new Vector.<Conteiner>(num_conteiner, true)
// conteiner width = 8 pixels (465/64), so it will have 64 conteiners (8²)
private var num_conteiner_row:uint = 8
private var conteiner_factor:Number = 6 // 2³ = 8
// temp
private var i:int, j:int, k:int
private var circle:Circle, conteiner:Conteiner, list:Vector.<Circle>
private var circle2:Circle
// collision
private var X:Number, Y:Number
private var dx:Number // distance x, or distance x²
private var dy:Number // same
private var d:Number // distance²
private var nx:Number // normal x
private var ny:Number // same
private var mx:Number // midPoint x
private var my:Number // same
private var dv:Number // sum of (velocity diference*normal)
private var vx:Number // something about velocity
private var vy:Number
// drawing
private var bitmapdata:BitmapData = new BitmapData(465, 465, true, 0xFFFFFF)
private var bitmap:Bitmap = new Bitmap(bitmapdata, "auto", true)
private var rect:Rectangle = new Rectangle(0, 0, 7, 7)
private var rect465:Rectangle = new Rectangle(0, 0, 465, 465)
private var point:Point = new Point()
private var col:ColorTransform = new ColorTransform(1,1,1,.1)
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);
stage.quality = StageQuality.LOW // less lagg
// listeners
stage.addEventListener(MouseEvent.CLICK, click)
stage.addEventListener(Event.ENTER_FRAME, ef)
building = true
// draw an circle shape and dopy its pixels
circle_shape = new Shape()
circle_shape.graphics.lineStyle(1, 0)
circle_shape.graphics.drawCircle(3, 3, 3)
circle_data = new BitmapData(7, 7, true, 0xFFFFFF)
circle_data.draw(circle_shape)
circle_shape.graphics.clear()
circle_shape = null
// build circle list
i = 0
circles[i] = new Circle(Math.random()*465, Math.random()*465, Math.random()-.5, Math.random())
while (++i < num_circles)
{
circles[i] = new Circle(Math.random() * 465, Math.random() * 465, Math.random() - .5, Math.random())
circles[i - 1].next = circles[i]
}
// build conteiner list
i = 0
conteiners[i] = new Conteiner()
while ( ++i < num_conteiner)
{
conteiners[i] = new Conteiner()
conteiners[i - 1].next = conteiners[i]
}
}
private function click(e:MouseEvent):void
{
if (building = !building)
{
stage.addEventListener(Event.ENTER_FRAME, ef)
} else
{
stage.removeEventListener(Event.ENTER_FRAME, ef)
}
}
private function ef(e:Event):void
{
// walk
walk()
// update conteiner list
conteiners_update()
// collisions
colsisions()
// draw screen
addChild(bitmap)
bitmapdata.colorTransform(rect465,col)
bitmapdata.lock()
circle = circles[0];
point.x = circle.x
point.y = circle.y
bitmapdata.copyPixels(circle_data, rect, point)
while (circle = circle.next)
{
point.x = circle.x
point.y = circle.y
bitmapdata.copyPixels(circle_data, rect, point)
}
bitmapdata.unlock()
}
private function colsisions():void
{
// on each conteiner, there's ball colision tests. The fisrt one:
conteiner = conteiners[0]
list = conteiner.list
i = -1
j = conteiner.list.length
while (++i < j)
{
X = list[i].x
Y = list[i].y
k = 0
while (++k < j)
{
if(i == k) continue;
// test collision
dx = X - list[k].x
dy = Y - list[k].y
if (9 > (d = (dx *= dx) + (dy *= dy)) )
{
solve_collision()
}
}
}
// others conteiners
while (conteiner = conteiner.next)
{
list = conteiner.list
i = -1
j = conteiner.list.length
while (++i < j)
{
X = list[i].x
Y = list[i].y
k = i
while (++k < j)
{
// test collision
dx = X - list[k].x
dy = Y - list[k].y
if (9 > (d = (dx *= dx) + (dy *= dy)) )
{
solve_collision()
}
}
}
}
}
private function solve_collision():void
{
circle = list[i]
circle2 = list[k]
// collision
nx = dx / d // normal
ny = dy / d
mx = (X + list[k].x) >> 1 // midpoint
my = (Y + list[k].y) >> 1
// positions
circle.x = mx - nx * 3
circle.y = my - ny * 3
circle2.x = mx + nx * 3
circle2.y = my + ny * 3
// velocity
dv = (circle.vx-circle2.vx)*nx + (circle.vy-circle2.vy)*ny
vx = dv * nx
vy = dv * ny
circle.vx -= vx
circle.vy -= vy
circle2.vx += vx
circle2.vy += vy
}
private function walk():void
{
circle = circles[0]
circle.x += circle.vx*=.99
circle.y += (circle.vy += .2)
if (circle.x > 465)
{
circle.x = 465
if (circle.vx > 0)
{
circle.vx *= -.9
}
} else if (circle.x < 0)
{
circle.x = 0
if (circle.vx < 0)
{
circle.vx *= -.9
}
}
if (circle.y < 0)
{
circle.y = 0
} else if (circle.y > 465)
{
circle.y = 465
if (circle.vy > 0)
{
circle.vy *= -.9
}
}
while (circle = circle.next)
{
circle.x += circle.vx
circle.y += (circle.vy += .2)
if (circle.x > 465)
{
circle.x = 465
if (circle.vx > 0)
{
circle.vx *= -.9
}
} else if (circle.x < 0)
{
circle.x = 0
if (circle.vx < 0)
{
circle.vx *= -.9
}
}
if (circle.y < 0)
{
circle.y = 0
} else if (circle.y > 465)
{
circle.y --
if (circle.vy > 0)
{
circle.vy *= -.9
}
}
}
}
private function conteiners_update():void
{
// clear conteiners Circle list
conteiner = conteiners[0]
conteiner.list = null
conteiner.list = new Vector.<Circle>()
while (conteiner = conteiner.next)
{
conteiner.list = null
conteiner.list = new Vector.<Circle>()
}
// buil conteiner list
circle = circles[0];
conteiners[((circle.y >> conteiner_factor) >> 0) * num_conteiner_row + ((circle.x >> conteiner_factor) >> 0)].list.push(circle)
while (circle = circle.next)
{
conteiners[((circle.y >> conteiner_factor) >> 0) * num_conteiner_row + ((circle.x >> conteiner_factor) >> 0)].list.push(circle)
}
}
}
}
//package
//{
/**
* ...
* @author Thi
*/
/*public*/ class Circle
{
public var x:Number, y:Number
public var vx:Number, vy:Number
public var next:Circle
public function Circle(x:Number, y:Number, vx:Number, vy:Number)
{
this.x = x
this.y = y
this.vx = vx
this.vy = vy
}
}
//}
//package
//{
/**
* ...
* @author Thi
*/
/*public*/ class Conteiner
{
public var list:Vector.<Circle> = new Vector.<Circle>()
public var length:int
public var next:Conteiner
public function Conteiner()
{
}
}
//}