粒子あやつる forked from: 流体パーティクル
--------------------------------------------------------------------------------//
http://wonderfl.net/code/23f89f2a5e8d9df21c8a72210c2a22c9c7490600
via StreamLine
http://gofar2.iobb.net/~htaka/wordpress/archives/953
フォースマップをマウスドラッグでいじります。
粒子はマウスから発生して、フォースマップに従って流れていきます。
スペースキーを押すと粒子表示/フォースマップ編集が切り替わります。
フォースマップ編集時には前に描いたフォースマップはリセットされます。
--------------------------------------------------------------------------------//
package
{
//--------------------------------------------------------------------------------//
// forked from 流体パーティクル
// http://wonderfl.net/code/23f89f2a5e8d9df21c8a72210c2a22c9c7490600
// via StreamLine
// http://gofar2.iobb.net/~htaka/wordpress/archives/953
//
// フォースマップをマウスドラッグでいじります。
// 粒子はマウスから発生して、フォースマップに従って流れていきます。
// スペースキーを押すと粒子表示/フォースマップ編集が切り替わります。
// フォースマップ編集時には前に描いたフォースマップはリセットされます。
//--------------------------------------------------------------------------------//
import frocessing.display.F5MovieClip2DBmp;
[SWF(width="465", height="465", frameRate="30")]
public class ForceMap2 extends F5MovieClip2DBmp
{
private var vectorF:VectorField;
private var strokeColor:Number;
private var numOfLine:int = 100;
private var myParticle:Array;
private var drawflg:int = 0;
public function ForceMap2()
{
super();
}
public function setup():void {
size(465,465);
background(0);
vectorF = new VectorField(this,width/20,height/20,0.1,54655465);
strokeColor = color(150,255,255,20);
var i:int;
myParticle = [];
for(i=0;i < numOfLine;i++){
myParticle[i] = new Particle(mouseX,mouseY,0,0,this,vectorF);
}
}
public function keyPressed():void {
switch(keyCode){
case 32:
if(drawflg==0) {
drawflg=1;
vectorF.resetVector();
} else {
drawflg=0;
}
break;
}
}
public function draw():void {
fill(0, 0, 0, 1);
noStroke();
rect(0, 0, width, height);
if(drawflg==0) {
noFill();
var i:int;
for(i=0;i<numOfLine;i++) {
myParticle[i].draw();
}
noStroke();
} else {
vectorF.drawVector()
}
}
}
}
class VectorField {
private var numOfCellX:int;
private var numOfCellY:int;
private var cellWidth:Number, cellHeight:Number;
public var cells:Array;
private var rootMC:F5MovieClip2DBmp;
private var mox:Number, moy:Number;
public function VectorField(_root:F5MovieClip2DBmp, _numOfCellX:int, _numOfCellY:int, noiseFactor:Number, seed:int) {
rootMC = _root;
numOfCellX = _numOfCellX;
numOfCellY = _numOfCellY;
cellWidth = rootMC.width / numOfCellX;
cellHeight = rootMC.height / numOfCellY;
mox = rootMC.mouseX;
moy = rootMC.mouseY;
var offsetAX:Number = rootMC.mouseX;
var offsetAY:Number = rootMC.mouseY;
var offsetBX:Number = (Math.random()*rootMC.width)-rootMC.width/2;
var offsetBY:Number = (Math.random()*rootMC.height)-rootMC.height/2;
var i:int;
var j:int;
cells = [];
for(i=0;i<numOfCellX+1; i++) {
cells[i]=[];
}
for(j=0;j<numOfCellY+1;j++) {
for(i=0;i<numOfCellX+1; i++) {
cells[i][j] = new Cell(i,j,
rootMC.noise((i + offsetAX) *noiseFactor, (j+offsetAY) * noiseFactor) - 0.5,
rootMC.noise((i+offsetBX) *noiseFactor, (j+offsetBY) * noiseFactor ) - 0.5,
cellWidth, cellHeight);
}
}
var gridData:Cell;
//隣接するグリッドをセットしていく。
for(j=0;j<numOfCellY+1;j++) {
for(i=0;i<numOfCellX+1; i++) {
gridData = cells[i][j];
if (j > 0) {
var up:Cell = cells[i][j - 1];//上
gridData.up = up;
up.low = gridData;//下
}
if (i > 0) {
var left:Cell = cells[i - 1][j];//左
gridData.left = left;
left.right = gridData;//右
}
if (j > 0 && i > 0) {
var upperLeft:Cell = cells[i - 1][j - 1];
gridData.upperLeft = upperLeft;
upperLeft.lowerRight = gridData;
}
if (j > 0 && i < numOfCellX - 1) {
var upperRight:Cell = cells[i + 1][j - 1];
gridData.upperRight = upperRight;
upperRight.lowerLeft = gridData;
}
}
}
}
public function getCell(_posX:Number,_posY:Number):Cell {
return cells[int(_posX/cellWidth)][int(_posY/cellHeight)];
}
public function getVecX(_posX:Number,_posY:Number):Number {
return cells[int(_posX/cellWidth)][int(_posY/cellHeight)].getVecX;
}
public function getVecY(_posX:Number,_posY:Number):Number {
return cells[int(_posX/cellWidth)][int(_posY/cellHeight)].getVecY;
}
public function drawGrid():void {
rootMC.noSmooth();
rootMC.stroke(128,128);
var i:int;
for(i=0;i<numOfCellX;i++) {
rootMC.line(cellWidth*i,0,cellWidth*i,rootMC.height);
}
for(i=0;i<numOfCellY;i++) {
rootMC.line(0,cellHeight*i,rootMC.width,cellHeight*i);
}
}
public function resetVector():void {
var i:int,j:int;
for(j=0;j<numOfCellY+1;j++) {
for(i=0;i<numOfCellX+1; i++) {
cells[i][j].resetVec();
}
}
}
public function drawVector():void {
var drawVectorLength:Number = (cellWidth+cellHeight)/2*10;
var mnx:Number = rootMC.mouseX;
var mny:Number = rootMC.mouseY;
rootMC.stroke(0xFFFFFF);
var i:int,j:int;
for(j=0;j<numOfCellY+1;j++) {
for(i=0;i<numOfCellX+1; i++) {
if(rootMC.isMousePressed){
cells[i][j].CulcMouseVec(mnx, mny, mnx-mox, mny-moy);
cells[i][j].updatePressure();
}
rootMC.line(cellWidth*i+cellWidth/2, cellHeight*j+cellHeight/2,cellWidth*i+cellWidth/2+cells[i][j].getVecX*drawVectorLength, cellHeight*j+cellHeight/2+cells[i][j].getVecY*drawVectorLength);
}
}
for(j=0;j<numOfCellY+1;j++) {
for(i=0;i<numOfCellX+1; i++) {
if(rootMC.isMousePressed)
cells[i][j].apdateVelocity();
}
}
mox = rootMC.mouseX;
moy = rootMC.mouseY;
}
}
import frocessing.display.F5MovieClip2DBmp;
import frocessing.math.Random;
import flash.geom.Rectangle;
class BaseGridData {
public var posX:int = 0;
public var posY:int = 0;
public var x:int = 0;
public var y:int = 0;
public var vecX:Number = 0;
public var vecY:Number = 0;
public var pressure:Number = 0;
public var color:Number = 0;
public var rgb:uint;
public var rectangle:Rectangle;
}
class NullGridData extends BaseGridData {}
class Cell extends BaseGridData {
private var cellWidth:Number, cellHeight:Number;
public function Cell(_posX:int, _posY:int, _vecX:Number, _vecY:Number, _cW:Number, _cH:Number) {
posX = _posX;
posY =_posY;
vecX = _vecX;
vecY = _vecY;
cellWidth = _cW;
cellHeight = _cH;
x = posX * cellWidth;
y = posY * cellHeight;
rectangle = new Rectangle(x, y, cellWidth, cellHeight);
}
//すべてのグリッドが8方向に隣接したグリッドを持つわけではないので、
//空のデータをセットしておく。
public var upperLeft:BaseGridData = new NullGridData();//左上
public var up:BaseGridData = new NullGridData();//上
public var upperRight:BaseGridData = new NullGridData();//右上
public var left:BaseGridData = new NullGridData();//左
public var right:BaseGridData = new NullGridData();//右
public var lowerLeft:BaseGridData = new NullGridData();//左下
public var low:BaseGridData = new NullGridData();//下
public var lowerRight:BaseGridData = new NullGridData();//右下
public function get getVecX():Number {
return vecX;
}
public function get getVecY():Number {
return vecY;
}
public function resetVec():void {
vecX = 0;
vecY = 0;
}
public function CulcMouseVec(mx:Number, my:Number, mvx:Number, mvy:Number):void {
var dx:Number = mx - posX*cellWidth;
var dy:Number = my - posY*cellHeight;
var distance:Number = Math.sqrt(dx*dx+dy*dy);
var penSize:Number = 40;
if(distance<penSize) {
if(distance<4) {
distance=penSize;
}
var power:Number = 0.005*penSize/distance;
vecX += mvx * power;
vecY += mvy * power;
}
}
public function updatePressure():void {
var pressureX:Number = (
upperLeft.vecX * 0.5 //左上
+ left.vecX //左
+ lowerLeft.vecX * 0.5 //左下
- upperRight.vecX * 0.5 //右上
- right.vecX //右
- lowerRight.vecX * 0.5 //右下
);
var pressureY:Number = (
upperLeft.vecY * 0.5 //左上
+ up.vecY //上
+ upperRight.vecY * 0.5 //右上
- lowerLeft.vecY * 0.5 //左下
- low.vecY //下
- lowerRight.vecY * 0.5 //右下
);
pressure = (pressureX + pressureY) * 0.25;
}
public function apdateVelocity():void {
vecX += (
upperLeft.pressure * 0.5 //左上
+ left.pressure //左
+ lowerLeft.pressure * 0.5 //左下
- upperRight.pressure * 0.5 //右上
- right.pressure //右
- lowerRight.pressure * 0.5 //右下
) * 0.25;
vecY += (
upperLeft.pressure * 0.5 //左上
+ up.pressure //上
+ upperRight.pressure * 0.5 //右上
- lowerLeft.pressure * 0.5 //左下
- low.pressure //下
- lowerRight.pressure * 0.5 //右下
) * 0.25;
vecX *= 0.99;
vecY *= 0.99;
}
}
class Particle {
public var posX:Number, posY:Number, oldPosX:Number, oldPosY:Number;
public var velocityX:Number, velocityY:Number;
public var noLineflg:Boolean = false;
private var root:F5MovieClip2DBmp;
private var vectorF:VectorField;
private var resolution:int = 10;
public function Particle(_px:Number,_py:Number,_velx:Number, _vely:Number, rMC:F5MovieClip2DBmp,vec:VectorField) {
root = rMC;
posX = _px;
posY = _py;
oldPosX = _px;
oldPosY = _py;
velocityX = _velx;
velocityY = _vely;
vectorF = vec;
noLineflg = false;
}
public function draw():void {
update();
if(noLineflg) {
oldPosX = posX;
oldPosY = posY;
noLineflg = false;
} else {
root.stroke(0xFFFFFF);
root.moveTo(posX, posY);
root.lineTo(oldPosX, oldPosY);
oldPosX = posX;
oldPosY = posY;
}
}
public function update():void {
if( (posX<0)||(posY<0)||(posX>root.width)||(posY>root.height) ) {
clear();
} else {
var absvX:Number = velocityX; //絶対値
absvX = absvX < 0 ? -absvX : absvX;
var absvY:Number = velocityY; //絶対値
absvY = absvY < 0 ? -absvY : absvY;
if(absvX<0.01&&absvY<0.01) {
clear();
return;
}
var _cell:Cell = vectorF.getCell(posX, posY);
var ax:Number = (posX % resolution) / resolution;
var ay:Number = (posY % resolution) / resolution;
velocityX += (1 - ax) * _cell.vecX * 0.5;
velocityY += (1 - ay) * _cell.vecY * 0.5;
velocityX += ax * _cell.right.vecX * 0.5;
velocityY += ax * _cell.right.vecY * 0.5;
velocityX += ay * _cell.low.vecX * 5;
velocityY += ay * _cell.low.vecY * 5;
velocityX += vectorF.getVecX(posX,posY);
velocityY += vectorF.getVecY(posX,posY);
posX += velocityX*5;
posY += velocityY*5;
velocityX *= 0.6;
velocityY *= 0.6;
}
}
private function clear():void {
posX = root.mouseX;
posY = root.mouseY;
velocityX = Math.random() * 10 - 5;
velocityY = Math.random() * 10 - 5;
noLineflg = true;
}
}