Last active
December 16, 2015 00:59
-
-
Save p5info/5351768 to your computer and use it in GitHub Desktop.
@fladdict さんの 「JSでアメーバのシミュレーション作ってみた (高速化編)」 http://fladdict.net/blog/2013/04/js-ameba-2.html のjavascriptソースコードをProcessing及びProcessing.jsで動くように修正してみた。動くように修正しただけなので、リファクタリングもかけてないですし、中のコメントも原則残したまんまです。 高速化前のソースhttps://gist.github.com/p5info/5343320
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Date; | |
int numberOfNodes = 200; | |
Node[] nodes = new Node[numberOfNodes]; | |
Edge[][] calcTable = new Edge[numberOfNodes][numberOfNodes]; | |
class Edge{ | |
float distX; | |
float distY; | |
float distance; | |
float angle; | |
} | |
void setup(){ | |
size(displayWidth, displayHeight); //Processing 2.x以降はdisplayWidth | |
//size(screenWidth, screenHeight); //if Processing 1.5.1まではscreenWidth | |
colorMode(RGB,255); | |
noSmooth(); | |
strokeCap(SQUARE); | |
background(0,0,0); | |
//@ //For FullScreen | |
//@ window.onresize = function() | |
//@ { | |
//@ size(window.innerWidth,window.innerHeight); | |
//@ }; | |
setup2(); | |
} | |
void setup2(){ | |
//高速化テーブル [NodeXId][NodeYId][dx,dy,dist]; | |
//あとで採用して最適化すること | |
for(int yy=0; yy<numberOfNodes; yy++){ | |
for(int xx=0; xx<numberOfNodes; xx++){ | |
calcTable[yy][xx]=new Edge(); | |
} | |
} | |
for(int i=0; i<numberOfNodes; i++){ | |
Node nd = new Node(); | |
nd.index = i; | |
nd.calcTable = calcTable; | |
nd.x = (random(1f)*width-1)+1; | |
nd.y = (random(1f)*height-1)+1; | |
nd.maxVelocity=6; | |
nd.friction = 0.9; | |
nd.nodes = nodes; | |
nd.nodeType = int(random(1f)*1.5 + random(1f)*1.2); | |
nodes[i]= nd;; | |
}; | |
} | |
void draw(){ | |
background(0); | |
//超高速化したので1回の描画に対して4回更新余裕っす | |
int n = nodes.length; | |
for(int h=0; h<4; h++){ | |
for(int i=0; i<n; i++) | |
{ | |
for(int j=i+1; j<n; j++) | |
{ | |
Node nd0 = nodes[i]; | |
Node nd1 = nodes[j]; | |
float dx = nd1.x - nd0.x; | |
float dy = nd1.y - nd0.y; | |
float dist = sqrt(dx*dx+dy*dy); | |
calcTable[i][j].distX = dx; | |
calcTable[i][j].distY = dy; | |
calcTable[i][j].distance = dist; | |
calcTable[i][j].angle = atan2(dy,dx); | |
calcTable[j][i].distX = -dx; | |
calcTable[j][i].distY = -dy; | |
calcTable[j][i].distance = dist; | |
calcTable[j][i].angle = atan2(-dy,-dx); | |
} | |
} | |
for(int i=0; i<n; i++){ | |
Node nd = nodes[i]; | |
nd.resetForce(); | |
nd.update(); | |
}; | |
} | |
/* | |
//距離その他、必要な計算をあらかじめ一括で行う | |
var n = nodes.length; | |
for(var i=0; i<n; i++) | |
{ | |
for(var j=i+1; j<n; j++) | |
{ | |
var nd0 = nodes[i]; | |
var nd1 = nodes[j]; | |
var dx = nd1.x - nd0.x; | |
var dy = nd1.y - nd0.y; | |
var dist = sqrt(dx*dx+dy*dy); | |
calcTable[i][j][0] = dx; | |
calcTable[i][j][1] = dy; | |
calcTable[i][j][2] = dist; | |
calcTable[i][j][3] = atan2(dy,dx); | |
calcTable[j][i][0] = -dx; | |
calcTable[j][i][1] = -dy; | |
calcTable[j][i][2] = dist; | |
calcTable[j][i][3] = atan2(-dy,-dx); | |
} | |
} | |
for(var i=0; i<n; i++){ | |
var nd = nodes[i]; | |
//超高速化したので1回の描画に対して3回更新しちゃおう | |
for(var j=0; j<3; j++){ | |
nd.resetForce(); | |
nd.update(); | |
} | |
};*/ | |
Date startDate = new Date(); | |
//noStroke(); | |
for(int i=0; i<n; i++) | |
{ | |
for(int j=i; j<n-1; j++) | |
{ | |
Node nd0 = nodes[i]; | |
Node nd1 = nodes[j]; | |
Edge table = calcTable[i][j]; | |
float dx = table.distX; | |
float dy = table.distY; | |
float dist = table.distance; | |
/* | |
var rad = atan2(dy,dx); | |
if(nd0.nodeType==nd1.nodeType && dist<150 && dist>2){ | |
var strokeCol = (150-dist)*1.5; | |
fill(strokeCol, strokeCol,0); | |
pushMatrix(); | |
translate(nd0.x, nd0.y); | |
rotate(rad); | |
scale(dist,1); | |
rect(0,0,1,1); | |
//line(nd0.x, nd0.y, nd1.x, nd1.y); | |
popMatrix(); | |
}*/ | |
if(nd0.nodeType==nd1.nodeType && dist<150 && dist>10){ | |
float strokeCol = (150-dist)*1.5; | |
stroke(strokeCol, strokeCol,0); | |
line(nd0.x, nd0.y, nd1.x, nd1.y); | |
} | |
} | |
} | |
for(int i=0; i<n; i++){ | |
Node nd = nodes[i]; | |
//nd.draw(); | |
}; | |
Date endDate = new Date(); | |
println(endDate.getTime()-startDate.getTime()); | |
} | |
class Node{ | |
int index = 0; | |
float x =0; | |
float y = 0; | |
float vx = 0; | |
float vy = 0; | |
int maxVelocity = 2; | |
float fx = 0; | |
float fy = 0; | |
int nodeType; | |
float rotation = 0; | |
Node[] nodes; | |
float friction = 0.9; | |
Edge[][] calcTable; | |
void init() | |
{ | |
} | |
void update() | |
{ | |
this.updateBoid(); | |
this.updateVelocity(); | |
this.updatePosition(); | |
} | |
void resetForce() | |
{ | |
this.fx = 0; | |
this.fy = 0; | |
} | |
//ここでBoid計算 | |
void updateBoid() | |
{ | |
int n = this.nodes.length; | |
//Calc Position | |
float fx = 0; | |
float fy = 0; | |
//仲間に近づく / 離れる | |
for(int i=0; i<n; i++){ | |
Node nd = this.nodes[i]; | |
if(nd==this) | |
continue; | |
Edge table = this.calcTable[this.index][nd.index]; | |
float dx = table.distX; | |
float dy = table.distY; | |
float dist = table.distance; | |
float rad = table.angle; | |
float dist2 = dist*dist; | |
//近づきすぎたら離れ、離れすぎたら近づく | |
if(dist<50 && dist>1){ | |
float dist3 = dist*dist*dist; | |
fx -= dx / dist3 * 40; | |
fy -= dy / dist3 * 40; | |
}else if(dist<200 && this.nodeType==nd.nodeType){ | |
float dist3 = dist*dist*dist; | |
fx += dx / dist3 * 30; | |
fy += dy / dist3 * 30; | |
} | |
//仲間と同じ方向に自走する | |
if(dist>1){ | |
float rad2 = atan2(nd.vy,nd.vx); //ここはテーブル化しちゃダメ!!(理由は考えよう!) | |
fx += cos(rad2) /dist2; | |
fy += sin(rad2) /dist2; | |
} | |
} | |
//マウスから逃げる | |
float mfx = mouseX - this.x; | |
float mfy = mouseY - this.y; | |
float mdistsq = mfx*mfx+mfy*mfy; | |
float mrad = atan2(mfy,mfx); | |
//console.log(mdist); | |
if(mdistsq>1){ | |
fx -= cos(mrad)/mdistsq*300; | |
fy -= sin(mrad)/mdistsq*300; | |
} | |
//@ //Normalize Speed | |
//@ var d = dist(fx,fy); | |
//@ if(d>1){ | |
//@ fx = fx / dist; | |
//@ fy = fy / dist; | |
//@ } | |
//ブラウン運動 | |
this.fx += (random(1f)-0.5)*0.2; | |
this.fy += (random(1f)-0.5)*0.2; | |
this.fx += fx * 3; | |
this.fy += fy * 3; | |
} | |
void updateVelocity() | |
{ | |
this.vx = this.vx * this.friction + this.fx; | |
this.vy = this.vy * this.friction + this.fy; | |
float v = sqrt(this.vx*this.vx+this.vy*this.vy); | |
if(v>this.maxVelocity){ | |
this.vx = this.vx / v * this.maxVelocity; | |
this.vy = this.vy / v * this.maxVelocity; | |
} | |
} | |
void updatePosition() | |
{ | |
this.x += this.vx; | |
this.y += this.vy; | |
if(this.x<0){ | |
this.x =0; | |
this.vx = abs(this.vx); | |
this.fx = 0; | |
}else if(this.x>width){ | |
this.x=width; | |
this.vx = -abs(this.vx); | |
this.fx = 0; | |
} | |
if(this.y<0){ | |
this.y=0; | |
this.vy = abs(this.vy); | |
this.fy = 0; | |
}else if(this.y>height){ | |
this.y=height; | |
this.vy = -abs(this.vy); | |
this.fy = 0; | |
} | |
} | |
void draw() | |
{ | |
stroke(150,150,0); | |
fill(0); | |
ellipse(this.x, this.y, 10,10); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment