5

そのため、私は数週間Processingに携わっており、プログラミングの経験はありませんが、より複雑なプロジェクトに移っています。ランダムなプロパティを持つクリーチャーを生成する進化シミュレーターをプログラミングしています。

最終的には複製を追加しますが、今のところ、生き物は画面の周りに浮かんでいて、マウスをいくらか追いかけています。ラインインの音と相互作用しますが、キャンバス上で見られるようにコメントアウトしましたので、あまり変わらないので、指摘したいと思いました。

現在のところ、フレームレートは私にとって理想的とは言えず、より多くのクリーチャーがスポーンされるにつれてゆっくりと低下します。根本的な間違いを犯しているのでしょうか、それともフレームごとに実行している関数が多すぎるのでしょうか。

これがソースコードで、ここのブラウザで遊ぶことができます:

//import ddf.minim.*;
//import ddf.minim.signals.*;
//import ddf.minim.analysis.*;
//import ddf.minim.effects.*;

//Minim minim;
//AudioInput in;
boolean newCreature = true;
boolean matured[];
int ellipses[];
int hair[];
int maxCreatureNumber = 75;
//int volume;
//int volumeTolerance = 1;
int creatureIndex = -1;
int creatureX[];
int creatureY[];
float strokeWeightAttribute[];
float creatureSize[];
float creatureEndSize[];
float creatureXIncrement[];
float creatureYIncrement[];
float bubbleSize;
float easing = 0.05;
float angle = 0.00;
color colorAttribute[];

void setup() {
    background(0);
    size(1000,500);
    noFill();
    //minim = new Minim(this);
    //in = minim.getLineIn(Minim.STEREO, 512);
    creatureX = new int[maxCreatureNumber];
    creatureY = new int[maxCreatureNumber];
    ellipses = new int[maxCreatureNumber];
    hair = new int[maxCreatureNumber];
    strokeWeightAttribute = new float[maxCreatureNumber];
    creatureEndSize = new float[maxCreatureNumber];
    creatureSize = new float[maxCreatureNumber];
    creatureXIncrement = new float[maxCreatureNumber];
    creatureYIncrement = new float[maxCreatureNumber];
    matured = new boolean[maxCreatureNumber];
    colorAttribute = new color[maxCreatureNumber];
}

void draw() {
  angle += 0.05;
  fill(0, 50);
  rect(-1, -1, 1001, 501);
  // for(int i = 0; i < in.bufferSize() - 1; i++) {
  //     if(in.mix.get(i) * 50 > volumeTolerance) {
  //         volume++;
  //     }
  // }
  if(newCreature && creatureIndex < maxCreatureNumber - 1) {
      initSpontaneousCreature();
  }
  updateCreatures();
  // bubbleSize = volume/250;
  bubbleSize += 0.01;
  // volume = 0;
}

//void stop() {
//    minim.stop();
//    super.stop();
//}

void initSpontaneousCreature() {
    creatureIndex++;
    creatureEndSize[creatureIndex] = int(random(5, 20));
    creatureX[creatureIndex] = int(random(1000));
    if(creatureX[creatureIndex] >= 500) {
        creatureX[creatureIndex] -= creatureEndSize[creatureIndex];
    }
    else {
        creatureX[creatureIndex] += creatureEndSize[creatureIndex];
    }
    creatureY[creatureIndex] = int(random(500));
    if(creatureY[creatureIndex] >= 250) {
        creatureY[creatureIndex] -= creatureEndSize[creatureIndex];
    }
    else {
        creatureY[creatureIndex] += creatureEndSize[creatureIndex];
    }
    ellipses[creatureIndex] = int(random(4));
    hair[creatureIndex] = int(random(4));
    strokeWeightAttribute[creatureIndex] = random(1, 4);
    colorAttribute[creatureIndex] = color(int(random(20,255)), int(random(20,255)), int(random(20,255)));
    matured[creatureIndex] = false;
    newCreature = false;
    while(ellipses[creatureIndex] == 0 && hair[creatureIndex] == 0) {
        ellipses[creatureIndex] = int(random(4));
        hair[creatureIndex] = int(random(4));
    }
}

void updateCreatures() {
    for(int n = 0; n <= creatureIndex; n++) {
        if(matured[n]) {
            creatureX[n] += ((((mouseX) - creatureX[n]) * easing) / (60/*-abs(volume/5))*/)) + random(-5, 6);
            creatureY[n] += ((((mouseY) -creatureY[n]) * easing) / (60/*-abs(/*volume/5))*/)) + random(-5,6);
            drawCreature();
        }
        else {
            if(creatureEndSize[n] != creatureSize[n]) {
                creatureSize[n] += bubbleSize;
                if(creatureSize[n] > creatureEndSize[n]) {
                    creatureSize[n] -= (creatureSize[n] - creatureEndSize[n]);
                }
            }
            else {
                newCreature = true;
                matured[n] = true;
                // bubbleSize = 0;
            }
            drawCreature();
        }
    }
}

void drawCreature() {
    for(int n = 0; n <= creatureIndex; n++) {
        if(matured[n]) {
            stroke(colorAttribute[n]);
            strokeWeight(strokeWeightAttribute[n]);
            for(int i = 0; i <= 4; i++) {
                if(ellipses[n] == i) {
                    if(i == 0) {

                    }
                    else if (i == 1) {
                      pushMatrix();
                      translate(creatureX[n], creatureY[n]);
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      rotate(radians(180));
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      popMatrix();
                    }
                    else if(i == 2) {
                      pushMatrix();
                      translate(creatureX[n], creatureY[n]);
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      rotate(radians(180));
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      rotate(radians(270));
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      popMatrix();

                    }
                    else if(i == 3) {
                      pushMatrix();
                      translate(creatureX[n], creatureY[n]);
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      rotate(radians(90));
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      rotate(radians(180));
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      rotate(radians(270));
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      popMatrix();
                    }
                }
                if(hair[n] == i) {
                    if(i == 0) {

                    }
                    else if (i == 1) {
                        pushMatrix();
                        translate(creatureX[n], creatureY[n]);
                        for(int j = 0; j <= 360; j+=70) {
                            rotate(j);
                            stroke(colorAttribute[n], random(255));
                            line(0,0, creatureSize[n] + random(10), creatureSize[n] + random(10));
                        }
                        popMatrix();
                    }
                    else if(i == 2) {
                        pushMatrix();
                        translate(creatureX[n], creatureY[n]);
                        for(int j = 0; j <= 360; j+=30) {
                            rotate(j);
                            stroke(colorAttribute[n], random(255));
                            line(0,0, creatureSize[n] + random(10), creatureSize[n] + random(10));
                        }
                        popMatrix();
                    }
                    else if(i == 3) {
                        pushMatrix();
                        translate(creatureX[n], creatureY[n]);
                        for(int j = 0; j <= 360; j+=1) {
                            rotate(j);
                            stroke(colorAttribute[n], random(255));
                            line(0,0, creatureSize[n] + random(10), creatureSize[n] + random(10));
                        }
                        popMatrix();
                    }
                }
            }
        }
        if(!matured[n]) {
            stroke(abs(sin(angle) * 255));
            //strokeWeight(5);
            ellipse(creatureX[n], creatureY[n], creatureSize[n] * 5,  creatureSize[n] * 5);
            noStroke();
        }
    }
}
4

3 に答える 3

14

そうですね、私が思ったように、不要なpushMatrix()呼び出しpopMatrix()や大量の行が主な原因のようでしたが、それでも冗長なコードがたくさんありました。

コードをよりクリーンな方法でリファクタリングしただけで、正常に実行されているようです。これが私の「改良された」バージョンです:

int maxCreatures = 75;
int numCreatures = 0;
int spawnNthFrame = 50;//spawn a creature every 50 frames
Creature[] creatures;

void setup() {
  background(0);
  size(1000,500);
  noFill();
  creatures = new Creature[maxCreatures];
}

void draw() {
  fill(0, 50);
  rect(-1, -1, 1001, 501);
  if(frameCount % spawnNthFrame == 0){
    println("creatures: " + numCreatures);
    if(numCreatures < maxCreatures) {
      //Creature constructor float endSize,int x, int y,int ellipses,int hair,float strokeW,color c
      creatures[numCreatures] = new Creature(random(5, 20),int(random(1000)),int(random(500)),int(random(4)),int(random(4)),random(1, 4),color(int(random(20,255)), int(random(20,255)), int(random(20,255))));
      numCreatures++;
    }
  }
  for(int i = 0; i < numCreatures; i++) creatures[i].update();
}

とクリーチャークラス:

class Creature{
 int x,y,cXInc,cYInc;//if x,y are ints, increments would be into, right?
 float cStrokeWeight,cSize,cEndSize,cSizeInc = 0.01,easing = 0.05,angle = 0.00;
 color cColor;
 int hair,numHair,ellipses;
 boolean matured = false;

 Creature(float endSize,int x, int y,int ellipses,int hair,float strokeW,color c){
    cEndSize = endSize;
    this.x = x;
    if(x >= 500) x -= cEndSize;
    else         x += cEndSize;
    this.y = y;
    if(y >= 250) x -= cEndSize;
    else         x += cEndSize;
    this.ellipses = ellipses;
    this.hair = hair;
    if(hair == 1) numHair = 3;//~5, half that, draw through centre, etc.
    if(hair == 2) numHair = 6;
    if(hair == 3) numHair = 30;//no default value
    cStrokeWeight = strokeW;
    this.cColor = c;
 }
 void update(){
   if(matured) { 
    x += (((mouseX - x) * easing) / 60) + random(-5, 6);
    y += (((mouseY - y) * easing) / 60) + random(-5, 6);
   }else {
    if(cSize < cEndSize) cSize += cSizeInc;
    else matured = true;
    angle += 0.05;
   } 
   this.draw();
 }
 void draw(){
   if(matured){
     stroke(cColor);
     strokeWeight(cStrokeWeight);
     if(ellipses == 1){//2 ellipses diagonally
       ellipse(x,y,cSize,cSize);
       ellipse(x+cSize,y+cSize,cSize,cSize);
     }
     if(ellipses == 2){
       ellipse(x,y,cSize,cSize);
       ellipse(x,y+cSize,cSize,cSize);
       ellipse(x+cSize,y+cSize,cSize,cSize);
     }
     if(ellipses == 3){
       ellipse(x,y,cSize,cSize);
       ellipse(x+cSize,y,cSize,cSize);
       ellipse(x,y+cSize,cSize,cSize);
       ellipse(x+cSize,y+cSize,cSize,cSize);
     }
     float hairAngleInc = TWO_PI/numHair;//angle increment for each piece = 360/number of hair lines
     float hairAngle,hairLength,hairCos,hairSin;
     for(int i = 0; i < numHair; i++){
       hairAngle = hairAngleInc * i;
       hairCos = cos(hairAngle);
       hairSin = sin(hairAngle);
       hairLength = random(20);
       stroke(cColor, random(255));
       line(x + (hairCos * -hairLength),y + (hairSin * -hairLength), x + (hairCos * hairLength),y + (hairSin * hairLength)); 
     }
   }else{
     stroke(abs(sin(angle) * 255));
     ellipse(x,y, cSize * 5,  cSize * 5);
   }
 }
}

さて、説明のために。

まず、1つのクリーチャーに関連するすべての変数を、スケッチの実行方法(スポーンされるクリーチャーの数など)を決定する「グローバル」変数から分離しました。

これにより、メインコードの長さは約25行になり、全体で100行より少し短くなります。これは元のコードの半分未満です。

最初の部分は特別なことは何もしません。draw()関数では、フレームごとにクリーチャーを作成する代わりに、 spawnNthFrame変数を使用してN番目のフレームごとに1つ描画します。これにより、クリーチャーのどの状態が遅くなったのかを簡単に確認できます。その変数に2のような小さな数を設定すると、フレームごとに多くのクリーチャーがスポーンするはずです。

Creatureクラスには、元のコードが配列に格納されているすべてのプロパティがあります。

する代わりに

pushMatrix();
translate();
ellipse();
rotate()
ellipse()
popMatrix();

x、yに楕円を描くだけです。回転に関するちょっとしたヒント。私はそれらが90度の増分であることに気づきました。処理には、ラジアンで90、180、360度の定数がいくつかあります。これは、HALF_PI、PI、TWO_PIであり、便利な場合があります。

さて、「毛深い」状況について、私が自分自身のためにコメントしたものがあります:

//if(i == 1) for(int j = 0; j <= 360; j+=70) , well 360/70 is about 5, if (i == 2) , 12 hair
//if = 3-> 360 lines ? do you really need that many lines, that thick ? how about 30 ? 5*12=60, but if you draw the lines through the centre, not from the centre, you can get away with half the lines

したがって、線を描画するための3つのループがあり、それぞれが異なる増分を持っています。基本的には360/70ライン、360/30ライン、360ラインのいずれかでした。およそ5、12、360行です。約5,12本の線については、中心からの「半径」の線ではなく、中心を横切る「直径」の線を引くことで、半分になりました。

これが私の言いたいことです、 ハーフライン

また、そのストロークウェイトとジッターモーションの360ラインは、おそらく数えにくいラインの束のように見えると思うので、なぜ髪を分割するのかと思いました。:P

たぶん、生き物は半径30、つまり直径30でかなり似ているでしょう。

ここで、これに使用される三角関数のビットを説明します。主なものは、「極からデカルトへの」座標変換です。

Polarは次のようになります。

「私は、角度(時計の1つのハンドルのように)と半径(中心からの距離)で表される方向に円を描いて移動しています。」

およびデカルト

「私はマンハッタンの街並みのように、 2つの軸(水平/Xと垂直/Y)に基づいて移動していますが、不正行為をしたり、壁を斜めに移動したりしています。」

それが理にかなっている場合...:)とにかく、次の式を使用して、角度と半径のペアをxとyのペアに変換します。

x = cos(angle) * radius
y = sin(angle) * radius

各行について:

angle = hairAngle
radius = hairLength

したがって、* x +(hairCos * -hairLength)*を含むline()は、次のようになります。

x + (hairCos * -hairLength) = 
move to x and from there move by hairLength
to the left(-) for the current angle (hairCos)

yについても同様ですが、cosを使用しているため、線の最初の点を中心から移動する角度の反対の直接(-hairLength)(クリーチャーのx)に配置し、2番目の点を「対角線」にします。'対角線'((-x、-y)から(+ x、+ y))を描画することを想像してみてください。ただし、これらも回転させます。

アップデート

どうやらこのコードをコピー/貼り付けすることはjavascriptでも機能します(Chromium / Chromeで最もよく表示されます)。ここで実行することもできます。

var maxCreatures = 75;
var numCreatures = 0;
var spawnNthFrame = 50;//spawn a creature every 50 frames
var creatures = [];

function setup() {
  background(0);
  createCanvas(1000,500);
  noFill();
}

function draw() {
  fill(0, 50);
  rect(-1, -1, 1001, 501);
  if(frameCount % spawnNthFrame === 0){
    println("creatures: " + numCreatures);
    if(numCreatures < maxCreatures) {
      //Creature constructor float endSize,int x, int y,int ellipses,int hair,float strokeW,color c
      creatures[numCreatures] = new Creature(random(5, 20),int(random(1000)),int(random(500)),int(random(4)),int(random(4)),random(1, 4),color(int(random(20,255)), int(random(20,255)), int(random(20,255))));
      numCreatures++;
    }
  }
  for(var i = 0; i < numCreatures; i++) creatures[i].update();
}




function Creature(endSize,x,y,ellipses,hair,strokeW,c){
 this.x = x;
 this.y = y;
 this.ellipses = ellipses;
 this.hair = hair;
 this.numHair = 0;
 this.cStrokeWeight = strokeW;
 this.cColor = c;
 this.cXInc = 0;
 this.cYInc = 0.01;
 this.cSize = 0;
 this.cEndSize = endSize;
 this.easing = 0.05;
 this.angle = 0.0;
 this.matured = false;
 
    if(x >= 500) x -= this.cEndSize;
    else         x += this.cEndSize;
    if(y >= 250) x -= this.cEndSize;
    else         x += this.cEndSize;
    if(hair == 1) this.numHair = 3;//~5, half that, draw through centre, etc.
    if(hair == 2) this.numHair = 6;
    if(hair == 3) this.numHair = 30;//no default value


 this.update = function(){
   if(this.matured) { 
    this.x += (((mouseX - this.x) * this.easing) / 60) + random(-5, 6);
    this.y += (((mouseY - this.y) * this.easing) / 60) + random(-5, 6);
   }else {
    if(this.cSize < this.cEndSize) this.cSize += this.cSizeInc;
    else this.matured = true;
    this.angle += 0.05;
   } 
   this.draw();
 }
 this.draw = function(){
   if(this.matured){
     stroke(this.cColor);
     strokeWeight(this.cStrokeWeight);
     if(this.ellipses == 1){//2 ellipses diagonally
       ellipse(this.x,this.y,this.cSize,this.cSize);
       ellipse(this.x+this.cSize,this.y+this.cSize,this.cSize,this.cSize);
     }
     if(this.ellipses == 2){
       ellipse(this.x,this.y,this.cSize,this.cSize);
       ellipse(this.x,this.y+this.cSize,this.cSize,this.cSize);
       ellipse(this.x+this.cSize,this.y+this.cSize,this.cSize,this.cSize);
     }
     if(this.ellipses == 3){
       ellipse(this.x,this.y,this.cSize,this.cSize);
       ellipse(this.x+this.cSize,this.y,this.cSize,this.cSize);
       ellipse(this.x,this.y+this.cSize,this.cSize,this.cSize);
       ellipse(this.x+this.cSize,this.y+this.cSize,this.cSize,this.cSize);
     }
     var hairAngleInc = TWO_PI/this.numHair;//angle increment for each piece = 360/number of hair lines
     var hairAngle,hairLength,hairCos,hairSin;
     for(var i = 0; i < this.numHair; i++){
       hairAngle = hairAngleInc * i;
       hairCos = cos(hairAngle);
       hairSin = sin(hairAngle);
       hairLength = random(20);
       stroke(this.cColor, random(255));
       line(this.x + (hairCos * -hairLength),this.y + (hairSin * -hairLength), this.x + (hairCos * hairLength),this.y + (hairSin * hairLength)); 
     }
   }else{
     stroke(abs(sin(this.angle) * 255));
     ellipse(this.x,this.y, this.cSize * 5,  this.cSize * 5);
   }
 }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.4/p5.min.js"></script>

クリーチャーJSスケッチプレビュー

于 2010-12-01T23:31:54.217 に答える
7

この関数を使用できますframeRate(fps)。何をするか、それは毎秒表示されるフレームの数を指定します。ただし、プロセッサが指定されたレートを維持するのに十分な速度でない場合、それは達成されません。たとえば、関数呼び出しframeRate(30)は1秒間に30回更新を試みます。フレームレートを。内に設定することをお勧めしますsetup()

draw()フレームレートを指定せずに使用すると、デフォルトで60fpsで実行されることを忘れないでください。

于 2010-12-01T15:05:34.453 に答える
7

さて、古き良きランダムポーズ方法があります。それは「貧乏人のプロファイラー」です。

数回スナップショットを撮るだけです。これにより、最も時間がかかっているものが正確に表示されます。これらは、より速く作成できるかどうかを確認する必要があるものです。フレームレートが高くなります。

于 2010-12-01T17:26:39.707 に答える