Liquid 3D 50,000
// forked from muta244's パーティクル高速化を整理. Liquid 250,000
// forked from fladdict's 250000 particle flow shimulation
// forked from fladdict's 20万個ぱーてぃくる 途中で飽きたけど 25万個は狙えるはず
// forked from beinteractive's forked from:10万個ぱーてぃくる - 軽く高速化
// forked from bkzen's 10万個ぱーてぃくる
package {
import flash.display.*;
import flash.events.*;
import net.hires.debug.Stats;
[SWF(backgroundColor = "0x000000", frameRate = "60")]
public class Main extends Sprite
{
protected const NUM_PARTICLES:int = 50000;
private var _world:ParticleWorld;
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);
_world = new ParticleWorld(
stage.stageWidth, stage.stageHeight, NUM_PARTICLES
);
addChild(_world.view);
var stats:Stats = new Stats();
stats.alpha = 0.75;
addChild(stats);
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.showDefaultContextMenu = false;
stage.addEventListener(Event.ENTER_FRAME, function ():void
{
_world.render();
});
}
}
}
import flash.display.*;
import flash.geom.*;
class ParticleWorld
{
public var view:Bitmap;
private var _w:int;
private var _h:int;
private var _mw:int;
private var _mh:int;
private var _colorTransform:ColorTransform;
private var _bitmapData:BitmapData;
private var _forceMap:BitmapData;
private var _xForces:Vector.<int>;
private var _yForces:Vector.<int>;
private var _zForces:Vector.<int>;
private var _starter:Particle;
private var _rect:Rectangle = new Rectangle();
private var _numFrames:int = 0;
public function ParticleWorld(w:int, h:int, numParticles:int):void
{
_w = w;
_h = h;
_mw = w >> 1;
_mh = h >> 1;
_colorTransform = new ColorTransform(0.70, 0.80, 0.80);
_bitmapData = new BitmapData(w, h, false);
_forceMap = new BitmapData(_mw, _mh, false);
_xForces = new Vector.<int>(_mw * _mh, true);
_yForces = new Vector.<int>(_mw * _mh, true);
_zForces = new Vector.<int>(_mw * _mh, true);
view = new Bitmap(_bitmapData);
var next:Particle;
for (var i:int = 0; i <= numParticles; i++) {
var p:Particle = new Particle();
p.x = Math.random() * w - w / 2;
p.y = Math.random() * h - h / 2;
p.z = Math.random() * h - h / 2;
p.next = next;
next = p;
if (i == numParticles) {
_starter = p;
}
}
_changeForce();
}
public function render():void
{
// _changeForce は重いので,
// 本当は次の _forceMap の生成をバックグラウンドで少しずつ行って,
// 完成したら切り替えるようにする.
if(_numFrames++ > 100){
_numFrames = 0;
_changeForce();
}
_bitmapData.lock();
_bitmapData.colorTransform(_bitmapData.rect, _colorTransform);
var w:int = Math.round(_w / 2);
var h:int = Math.round(_h / 2);
var p:Particle = _starter;
while (p = p.next) {
var i:int = (p.y + h >> 2) * _mw + (p.x + w >> 2);
// パーティクルの座標が重なった場合の対策をしないと同じ動きをして意味がないので,
// 乱数を持たせた p.factor を掛け合わせて力に揺らぎを与える.
p.vx = p.vx * 0.99 + _xForces[i] * p.factor;
p.vy = p.vy * 0.99 + _yForces[i] * p.factor;
p.vz = p.vz * 0.99 + _zForces[i] * p.factor;
p.x += int(p.vx);
p.y += int(p.vy);
p.z += int(p.vz);
if (p.x < -w) p.x += _w;
else if (p.x >= w) p.x -= _w;
if (p.y < -h) p.y += _h;
else if (p.y >= h) p.y -= _h;
if (p.z < 0) p.z += _h;
else if (p.z >= _h) p.z -= _h;
var f:Number = 100 / (100 + p.z);
_rect.width = _rect.height = 4 * f;
_rect.x = p.x * f + w;
_rect.y = p.y * f + h;
_bitmapData.fillRect(_rect, 0xFFFFFFFF);
}
_bitmapData.unlock();
}
private function _changeForce():void
{
_forceMap.perlinNoise(
_mw / 2, _mh / 2, 8, 0xFFFFFF * Math.random(), false, true, 7, false
);
//_forceMap をキャッシュ
for(var y:int = 0; y < _mh; y++){
for(var x:int = 0; x < _mw; x++){
var color:int = _forceMap.getPixel(x, y);
var i:int = y * _mw + x;
_xForces[i] = (color >> 16 & 0xff) - 0x80;
_yForces[i] = (color >> 8 & 0xff) - 0x80;
_zForces[i] = (color & 0xff) - 0x80;
}
}
}
}
class Particle
{
public var x:int = 0;
public var y:int = 0;
public var z:int = 0;
public var vx:Number = 0;
public var vy:Number = 0;
public var vz:Number = 0;
public var factor:Number = (Math.random() * 0.2 + 0.9) * 0.003;
public var next:Particle;
}