Skip to content

Instantly share code, notes, and snippets.

@p5info
Last active December 16, 2015 00:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save p5info/5351768 to your computer and use it in GitHub Desktop.
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
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