forked from: ナウシカのラストの王蟲のグジャグジャってこんな感じだよね
なんかいっぱい動かすテスト
洗濯機みたいになってます。
@author jc at bk-zen.com
// forked from fladdict's ナウシカのラストの王蟲のグジャグジャってこんな感じだよね
// 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.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import net.hires.debug.Stats;
/**
* なんかいっぱい動かすテスト
* 洗濯機みたいになってます。
* @author jc at bk-zen.com
*/
[SWF(backgroundColor = "0x000000", frameRate = "30")]
public class Test3 extends Sprite
{
protected const NUM_OF_PARTICLES: int = 3000;
private var main: TestMain;
public function Test3()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
//
main = new TestMain(stage.stageWidth, stage.stageHeight, NUM_OF_PARTICLES);
addChild(main.view);
addChild(new Stats());
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.addEventListener(Event.RESIZE, onResize);
stage.addEventListener(MouseEvent.CLICK, onClick);
addEventListener(Event.ENTER_FRAME, onEnter);
}
private function onClick(e:MouseEvent):void
{
main.change();
}
private function onEnter(e:Event):void
{
main.draw(mouseX, mouseY);
}
// りサイズ (未実装)
private function onResize(e:Event):void
{
main.resize(stage.stageWidth, stage.stageHeight);
}
}
}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.ColorTransform;
import flash.geom.Point;
import flash.utils.ByteArray;
class TestMain
{
private var w: int;
private var h: int;
private var mw: int;
private var mh: int;
public var view: Bitmap;
private var bmpData: BitmapData;
private var forceMap: BitmapData;
private var forceCache: Array;
private var randomSeed: int;
private var particles: Particle;
private var num: int;
private var color: uint = 0xF0F0FF;
private var count: int = 0;
private var colorTr: ColorTransform;
private var cnt:int = 0;
//forcemap を getPixel で計算すると重いので、色はキャッシュする。
private var forceVector:Vector.<int>;
private var fxVector:Vector.<int>;
private var fyVector:Vector.<int>;
public function TestMain(w: int, h: int, numOfParticles: int)
{
this.w = w;
mw = w >> 1;
this.h = h;
mh = h >> 1;
bmpData = new BitmapData(w, h, false, 0x00000000);
forceMap = new BitmapData(mw, mh, false);
view = new Bitmap(bmpData);
num = numOfParticles;
var i: int;
var prev: Particle = particles = new Particle();
var p: Particle;
while (++i <= num)
{
p = new Particle();
p.x = Math.random() * w;
p.y = Math.random() * h;
p.rnd = (Math.random()*0.2 + 0.9) * 0.003;
prev.next = p;
prev = p;
}
colorTr = new ColorTransform(1, 1, 1, 1, -2, -1, -1);
change();
}
// 描画、マウスの判定を後で追加予定
public function draw(mouseX: Number, mouseY: Number): void
{
cnt++;
if(cnt>100){
change();
cnt = 0;
}
var p: Particle = particles;
var col: uint;
var forceIndex:int;
bmpData.lock();
bmpData.colorTransform(bmpData.rect, colorTr);
while ((p = p.next) != null)
{
forceIndex = (p.y>>2) * mw + (p.x>>2);
//2万個以上はパーティクルの座標が重なった場合の対策をしないと、
//まったく同じ動きをするので意味がないので p.rndに乱数を持たせて、力に揺らぎを与える。
p.vx = p.vx * 0.99 + fxVector[forceIndex] * p.rnd;
p.vy = p.vy * 0.99 + fyVector[forceIndex] * p.rnd;
p.px = p.x;
p.py = p.y;
p.x += p.vx;
p.y += p.vy;
var isDraw:Boolean = true;
if (p.x < 0){
p.x += w;
isDraw = false;
}else if ((p.x >= w) )
{
p.x -= w
isDraw = false;
};
if(p.y < 0)
{
p.y += h;
isDraw = false;
}else if (p.y >= h)
{
p.y -= h;
isDraw = false;
}
//bmpData.setPixel(p.x >> 0, p.y >> 0, p.col);
if(isDraw){
lineTo(p.px, p.py, p.x, p.y);
}
}
bmpData.unlock();
}
public function change(): void
{
/**
この処理は重いので、本当は次のforcemapの生成をバックグラウンドで少しづつ行って、完成したら切り替えるようにする。
*/
forceMap.perlinNoise(64, 64, 16, Math.random() * 0xFFFF, false, true, 7, false);
if(!forceVector){
fxVector = new Vector.<int>(mw*mh,true);
fyVector = new Vector.<int>(mw*mh,true);
}
//force mapをキャッシュする
for(var yy:int=0; yy<mh; yy++){
for(var xx:int=0; xx<mw; xx++){
var col:int = forceMap.getPixel(xx,yy);
var pos:int = yy*mw+xx;
fxVector[pos] = (col>>16&0xff)-128;
fyVector[pos] = (col>>8&0xff)-128;
}
}
}
public function lineTo(x0:Number, y0:Number, x1:Number, y1:Number): void
{
var dx:int = ( x1 > x0 ) ? x1 - x0 : x0 - x1;
var dy:int = ( y1 > y0 ) ? y1 - y0 : y0 - y1;
var sx:int = ( x1 > x0 ) ? 1 : -1;
var sy:int = ( y1 > y0 ) ? 1 : -1;
var i:int, E:int;
var col:int;
var r:int, g:int, b:int;
if ( dx > dy ) {
E = -dx;
for (i = 0 ; i <= dx ; i++ ) {
col = bmpData.getPixel(x0,y0);
r = ((col>>16&0xff) *0.7 + 0xff*0.3);
g = ((col>>8&0xff) *0.7 + 0xff*0.3);
b = ((col>>0xff)*0.6 + 0xff*0.2);
bmpData.setPixel(x0, y0,(r<<16)|(g<<8)|b);
x0 += sx;
E += 2 * dy;
if ( E >= 0 ) {
y0 += sy;
E -= 2 * dx;
}
}
} else {
E = -dy;
for (i = 0 ; i <= dy ; i++ ) {
col = bmpData.getPixel(x0,y0);
r = ((col>>16&0xff) + 0xff) >> 1;
g = ((col>>8&0xff) + 0xff) >> 1;
b = ((col>>0xff) + 0xff) >> 1;
bmpData.setPixel(x0, y0,(r<<16)|(g<<8)|b);
y0 += sy;
E += 2 * dx;
if ( E >= 0 ) {
x0 += sx;
E -= 2 * dy;
}
}
}
}
public function resize(w: Number, h: Number): void
{
this.w = w;
this.h = h;
if (bmpData)
{
bmpData.dispose();
}
bmpData = new BitmapData(w, h, false, 0x00000000);
view.bitmapData = bmpData;
}
}
class Particle
{
public var x: Number = 0;
public var y: Number = 0;
public var px:Number = 0;
public var py:Number = 0;
public var vx: Number = 0;
public var vy: Number = 0;
public var rnd: Number = 0;
public var col:int= 0xffffff;
public var next: Particle;
public function Particle()
{
}
}