forked from: ラザフォードの実験
forked from ラザフォードの実験 (diff: 154)
import net.hires.debug.Stats;
ActionScript3 source code
/**
* Copyright Nicolas ( http://wonderfl.net/user/Nicolas )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/yeVb
*/
// forked from Nicolas's ラザフォードの実験
// forked from Nicolas's パーティクル
package {
import flash.geom.Rectangle;
import flash.display.Graphics;
import flash.display.Shape;
import flash.events.*;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.display.Sprite;
import net.hires.debug.Stats;
[SWF(frameRate="60")]
public class LorentzForce extends Sprite
{
private const WIDTH:int = 465;
private const HEIGHT:int = 465;
private var bmp:Bitmap;
private var bmd:BitmapData;
private var updater:LorentzForceUpdater;
private var renderer:Renderer;
private var poolSize:int = 1000;
private var pool:ParticlePool;
private var count:int = 0;
public function LorentzForce()
{
bmd = new BitmapData(WIDTH, HEIGHT, false, 0x000000);
bmp = addChild(new Bitmap(bmd)) as Bitmap;
ParticlePool.setPoolSize(poolSize);
pool = ParticlePool.getInstance();
var sp:Sprite = new Sprite();
sp.graphics.beginFill(0x00FF00, 0.3);
sp.graphics.drawRect(300,0,150,500);
addChild(sp);
var field:MagneticField = new MagneticField(0.3, sp);
var sp2:Sprite = new Sprite();
sp2.graphics.beginFill(0x00FF00, 0.3);
sp2.graphics.drawRect(0,0,150,300);
addChild(sp2);
var field2:MagneticField = new MagneticField(-0.5, sp2);
updater = new LorentzForceUpdater(WIDTH, HEIGHT);
updater.fields.push(field, field2);
renderer = new Renderer(bmd);
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
stage.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void {
buttonDown = true;
});
stage.addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void {
buttonDown = false;
});
addChild(new Stats());
}
private var buttonDown:Boolean = false;
private function enterFrameHandler(e:Event):void
{
if(buttonDown) {
var p:Particle = pool.acquire();
p.x = 0;
p.y = 400 + Math.random() * 3;
p.vx = 20;
p.vy = 0;
}
updater.update();
renderer.render();
//count++;
}
}
}
import flash.geom.Vector3D;
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.9, 0.9, 0.9);
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 var t:Number = 0;
public var dt:Number = 0.1;
//temp
private var x:Number = 0;
private var y:Number = 0;
private var vx:Number = 0;
private var vy:Number = 0;
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];
this.x = p.x;
this.y = p.y;
this.vx = p.vx;
this.vy = p.vy;
//4次のルンゲクッタ法を、x,y,vx,vyについて連立
var k1:Vector.<Number> = new Vector.<Number>(4);
var k2:Vector.<Number> = new Vector.<Number>(4);
var k3:Vector.<Number> = new Vector.<Number>(4);
var k4:Vector.<Number> = new Vector.<Number>(4);
k1[0] = dt * fx(t, x, y, vx, vy);
k1[1] = dt * fy(t, x, y, vx, vy);
k1[2] = dt * fvx(t, x, y, vx, vy);
k1[3] = dt * fvy(t, x, y, vx, vy);
k2[0] = dt * fx(t + dt / 2, x + k1[0] / 2, y + k1[1] / 2, vx + k1[2] / 2, vy + k1[3] / 2);
k2[1] = dt * fy(t + dt / 2, x + k1[0] / 2, y + k1[1] / 2, vx + k1[2] / 2, vy + k1[3] / 2);
k2[2] = dt * fvx(t + dt / 2, x + k1[0] / 2, y + k1[1] / 2, vx + k1[2] / 2, vy + k1[3] / 2);
k2[3] = dt * fvy(t + dt / 2, x + k1[0] / 2, y + k1[1] / 2, vx + k1[2] / 2, vy + k1[3] / 2);
k3[0] = dt * fx(t + dt / 2, x + k2[0] / 2, y + k2[1] / 2, vx + k2[2] / 2, vy + k2[3] / 2);
k3[1] = dt * fy(t + dt / 2, x + k2[0] / 2, y + k2[1] / 2, vx + k2[2] / 2, vy + k2[3] / 2);
k3[2] = dt * fvx(t + dt / 2, x + k2[0] / 2, y + k2[1] / 2, vx + k2[2] / 2, vy + k2[3] / 2);
k3[3] = dt * fvy(t + dt / 2, x + k2[0] / 2, y + k2[1] / 2, vx + k2[2] / 2, vy + k2[3] / 2);
k4[0] = dt * fx(t + dt, x + k3[0], y + k3[1], vx + k3[2], vy + k3[3]);
k4[1] = dt * fy(t + dt, x + k3[0], y + k3[1], vx + k3[2], vy + k3[3]);
k4[2] = dt * fvx(t + dt, x + k3[0], y + k3[1], vx + k3[2], vy + k3[3]);
k4[3] = dt * fvy(t + dt, x + k3[0], y + k3[1], vx + k3[2], vy + k3[3]);
p.x += (k1[0] + k2[0] * 2 + k3[0] * 2 + k4[0]) / 6;
p.y += (k1[1] + k2[1] * 2 + k3[1] * 2 + k4[1]) / 6;
p.vx += (k1[2] + k2[2] * 2 + k3[2] * 2 + k4[2]) / 6;
p.vy += (k1[3] + k2[3] * 2 + k3[3] * 2 + k4[3]) / 6;
if(p.x < 0 || p.x > bmdWidth || p.y < 0 || p.y > bmdHeight)
{
pool.release(p);
len--;
}
}
}
public function fx(t:Number, x:Number, y:Number, vx:Number, vy:Number):Number
{
return 0;
}
public function fy(t:Number, x:Number, y:Number, vx:Number, vy:Number):Number
{
return 0;
}
public function fvx(t:Number, x:Number, y:Number, vx:Number, vy:Number):Number
{
return 0;
}
public function fvy(t:Number, x:Number, y:Number, vx:Number, vy:Number):Number
{
return 0;
}
}
import flash.display.Sprite;
class LorentzForceUpdater extends Updater
{
public var fields:Vector.<MagneticField>;
public function LorentzForceUpdater(width:int, height:int)
{
super(width, height);
fields = new Vector.<MagneticField>();
}
override public function fx(t:Number, x:Number, y:Number, vx:Number, vy:Number):Number
{
return vx;
}
override public function fy(t:Number, x:Number, y:Number, vx:Number, vy:Number):Number
{
return vy;
}
override public function fvx(t:Number, x:Number, y:Number, vx:Number, vy:Number):Number
{
var dst:Number = 0;
var numFields:int = fields.length;
for (var i:int = 0; i < numFields; i++) {
if(fields[i].area.hitTestPoint(x, y, true)){
dst += vy * fields[i].B;
}
}
return dst;
}
override public function fvy(t:Number, x:Number, y:Number, vx:Number, vy:Number):Number
{
var dst:Number = 0;
var numFields:int = fields.length;
for (var i:int = 0; i < numFields; i++) {
if(fields[i].area.hitTestPoint(x, y, true)){
dst -= vx * fields[i].B;
}
}
return dst;
}
}
class MagneticField
{
public var B:Number;
public var area:Sprite;
public function MagneticField(B:Number, area:Sprite)
{
this.B = B;
this.area = area;
}
}
class Particle
{
public var x:Number;
public var y:Number;
public var vx:Number;
public var vy: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 {}
