/**
* Copyright aobyrne ( http://wonderfl.net/user/aobyrne )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/fKtr
*/
// forked from Nicolas's ラザフォードの実験
// forked from Nicolas's パーティクル
package {
import flash.display.Graphics;
import flash.display.Shape;
import flash.events.Event;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.display.Sprite;
import net.hires.debug.Stats;
[SWF(frameRate="60")]
public class FlashTest extends Sprite
{
private const WIDTH:int = 465;
private const HEIGHT:int = 465;
private var bmp:Bitmap;
private var bmd:BitmapData;
private var updater:Updater;
private var renderer:Renderer;
private var poolSize:int = 2000;
private var pool:ParticlePool;
private var count:int = 0;
private var gold:Shape;
public function FlashTest()
{
bmd = new BitmapData(WIDTH, HEIGHT, false, 0x000000);
bmp = addChild(new Bitmap(bmd)) as Bitmap;
ParticlePool.setPoolSize(poolSize);
pool = ParticlePool.getInstance();
gold = addChild(new Shape()) as Shape;
gold.x = 400;
gold.y = 232;
var g:Graphics = gold.graphics;
g.beginFill(0xFFFF00);
g.drawCircle(0, 0, 2);
g.endFill();
updater = new CoulombicForceUpdater(WIDTH, HEIGHT, gold.x, gold.y, 50);
renderer = new Renderer(bmd);
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
addChild(new Stats());
}
private function enterFrameHandler(e:Event):void
{
var p:Particle = pool.acquire();
p.x = 0;
p.y = Math.random() * 265 + 100;
p.vx = 2;
p.vy = 0;
updater.update();
renderer.render();
count++;
}
}
}
import flash.geom.ColorTransform;
import flash.geom.Rectangle;
import flash.display.BitmapData;
class Renderer
{
private var targetBmd:BitmapData
private var rect:Rectangle;
private var colorTransform:ColorTransform;
private var pool:ParticlePool;
public function Renderer(bmd:BitmapData)
{
targetBmd = bmd;
rect = targetBmd.rect;
colorTransform = new ColorTransform(0.99, 0.99, 0.99);
pool = ParticlePool.getInstance();
}
public function render():void
{
targetBmd.lock();
targetBmd.colorTransform(targetBmd.rect, colorTransform);
var len:int = pool.livingParticles.length;
var p:Particle;
for (var i:int = 0; i < len; i++)
{
p = pool.livingParticles[i];
targetBmd.setPixel(p.x, p.y, 0xFFFFFF);
}
targetBmd.unlock();
}
}
class Updater
{
private var bmdWidth:int;
private var bmdHeight:int;
protected var pool:ParticlePool;
public function Updater(width:int, height:int)
{
bmdWidth = width;
bmdHeight = height;
pool = ParticlePool.getInstance();
}
public function update():void
{
var len:int = pool.livingParticles.length;
var p:Particle;
for (var i:int = 0; i < len; i++)
{
p = pool.livingParticles[i];
p.vx += p.ax;
p.vy += p.ay;
p.x += p.vx;
p.y += p.vy;
if(p.x < 0 || p.x > bmdWidth || p.y < 0 || p.y > bmdHeight)
{
pool.release(p);
len--;
}
}
}
}
class CoulombicForceUpdater extends Updater
{
private var targetX:Number;
private var targetY:Number;
private var k:Number;
public function CoulombicForceUpdater(width:int, height:int, targetX:Number, targetY:Number, k:Number)
{
super(width, height);
this.targetX = targetX;
this.targetY = targetY;
this.k = k;
}
override public function update():void
{
var len:int = pool.livingParticles.length;
var p:Particle;
var squareOfDistance:Number;
var force:Number;
var angle:Number;
for (var i:int = 0; i < len; i++)
{
p = pool.livingParticles[i];
squareOfDistance = (p.x - targetX) * (p.x - targetX) + (p.y - targetY) * (p.y - targetY);
force = -k / squareOfDistance;
angle = Math.atan2(p.y - targetY, p.x - targetX);
p.ax = Math.cos(angle) * force;
p.ay = Math.sin(angle) * force;
}
super.update();
}
}
class Particle
{
public var x:Number;
public var y:Number;
public var vx:Number;
public var vy:Number;
public var ax:Number;
public var ay:Number;
public function Particle()
{
}
}
class NullParticle extends Particle
{
private static var _instance:NullParticle;
public function NullParticle(s:SingletonEnforcer)
{
if (!s) throw new Error("Singleton Error");
}
public static function getInstance():NullParticle
{
if (!_instance) return new NullParticle(new SingletonEnforcer());
else return _instance;
}
}
class ParticlePool
{
private static var _instance:ParticlePool;
private static var _poolSize:int;
private var _livingParticles:Vector.<Particle>;
private var _deadParticles:Vector.<Particle>;
public function ParticlePool(s:SingletonEnforcer)
{
if (!s) throw new Error("Singleton Error");
_deadParticles = new Vector.<Particle>();
for (var i:int = 0; i < _poolSize; i++)
{
_deadParticles[i] = new Particle();
}
_livingParticles = new Vector.<Particle>();
}
public static function setPoolSize(n:int):void
{
if (!_instance) _poolSize = n;
else throw new Error("setPoolSize() must be used before creating ParticlePool instance");
}
public static function getInstance():ParticlePool
{
if (!_instance) _instance = new ParticlePool(new SingletonEnforcer());
return _instance;
}
public function acquire():Particle
{
var p:Particle;
if (_deadParticles.length > 0) {
p = _deadParticles.pop();
_livingParticles.push(p);
}
else p = NullParticle.getInstance();
return p;
}
public function release(p:Particle):void
{
var index:int = _livingParticles.indexOf(p);
_livingParticles.splice(index, 1);
_deadParticles.push(p);
}
public function get livingParticles():Vector.<Particle> { return _livingParticles; }
}
class SingletonEnforcer {}