处理:如何提高程序的帧速率?

发布于 2024-10-05 11:22:39 字数 8185 浏览 4 评论 0原文

所以我已经在处理工作了几个星期了,而且,尽管我在编程方面没有经验,但我已经转向更复杂的项目。我正在编写一个进化模拟器,它会产生具有随机属性的生物。

最终,我将添加繁殖,但到目前为止,这些生物只是漂浮在屏幕上,并在某种程度上跟随鼠标。它与来自线路的声音交互,但我注释掉了这些部分,以便可以在画布上查看它,它不应该真正改变问题,我只是想我会指出这一点。

到目前为止,帧速率对我来说远不理想,并且随着更多生物的产生,帧速率慢慢降低。我是否犯了一些根本性错误,或者我只是每帧运行了太多函数?

这是源代码,您可以在浏览器中使用它这里< /a>:

//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();
        }
    }
}

So I've been working in Processing for a few weeks now, and, though I'm not experienced in programming, I have moved on to more complex projects. I'm programming an evolution simulator, that spawns creatures with random properties.

Eventually, I'll add reproduction, but as of now the creatures just sort of float around the screen, and follow the mouse somewhat. It interacts with sound from the line in, but I commented those parts out so that it can be viewed on the canvas, it shouldn't really change the question, I just thought I would point it out.

As of now, the framerate is far less than ideal for me, and it slowly lowers as more creatures are spawned. Am I making some fundamental mistake, or am I just running too many functions per frame?

Here's the source code, and you can play with it in the browser here:

//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();
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

清醇 2024-10-12 11:22:39

是的,正如我所怀疑的,所有不必要的 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();
}

和 Creature 类:

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);
   }
 }
}

好的,现在进行解释。

首先,我将与一个生物相关的所有变量与决定草图如何运行的“全局”变量分开(生成多少个生物等)。

这使得主代码长约 25 行,总共略低于 100 行,不到原始代码的一半。

第一部分没有做任何特别的事情。在 draw() 函数中,我没有每帧创建一个生物,而是使用 spawnNthFrame 变量每第 N 帧绘制一个生物,这样可以轻松查看生物的状态生物让它变慢。如果你为该变量设置一个像 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 条线,我通过在中心绘制“直径”线而不是从中心绘制“半径”线,将其减半。

这就是我的意思,
halfLines

另外,我认为具有该描边重量和抖动运动的 360 条线可能看起来像一堆难以计数的线,所以我想,为什么要分叉头发呢? :P

也许这个生物看起来非常相似,有大约 60 个半径,这意味着 30 个直径。

现在解释一些用于此目的的三角函数。
最主要的是“极坐标到笛卡尔坐标”的转换:

极坐标类似于:

“我在一个圆上向一个角度描述的方向移动(很像时钟的一个手柄)并且半径(距中心的距离)。”

和笛卡尔

“我基于两个(水平/X和垂直/Y)移动,有点像曼哈顿的街道,但我作弊,也沿着对角线穿过墙壁移动。”

如果这有任何意义的话......:)
无论如何,您可以使用以下公式将角度和半径对转换为x和y对:

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

对于每条线:

angle = hairAngle
radius = hairLength

因此line() *x + (hairCos * -hairLength)* 看起来有点像这样:

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

与 y 类似,但使用 cos,因此这会将线的第一个点置于从中心移动的角度的相反直线 (-hairLength) 上(其中是生物的 x),第二个是“对角线”。想象一下绘制“对角线”(从 (-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 草图预览

Right, as I suspected, all the unnecessary pushMatrix(), popMatrix() calls and the large amount of lines seemed to be the main culprits, still, there was a lot of redundant code.

I simply refactored the code in a cleaner manner and it seems to run fine.
Here is my 'improved' version:

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();
}

and the Creature class:

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);
   }
 }
}

Ok, now for the explanations.

First, I separated all the variables that were related to one creature from the 'global' ones that determine how the sketch runs (how many creatures get spawned, etc.).

This makes the main code about 25 lines long and altogether a bit below 100 lines which is less than half of the original.

The first part doesn't do anything special. In the draw() function, instead of creating a Creature every frame, I draw one every Nth frame using the spawnNthFrame variable, this made it easy to see which state of the creature made it slow. If you set a small number like 2 to that variable it should spawn a lot of creatures per frame.

The Creature class has all the properties the original code stored in arrays.

Instead of doing

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

I simply draw the ellipses at x,y.
A little hint on the rotations. I've noticed they were increments
of 90 degrees. Processing has some nice constants for 90,180,360 degrees
in radians: HALF_PI, PI, TWO_PI which can be handy sometimes.

Now for the 'hairy' situation, here's something I commented out for myself:

//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

So there were 3 loops for drawing lines, each having different increments. Basically
there were either 360/70 lines, 360/30 lines and 360 lines.
Roughly about 5,12 and 360 lines. About the 5,12 lines, I kind of halved that by drawing 'diameter' lines across the centre as opposed to 'radius' lines from the centre.

Here's what I mean,
halfLines

Also I think that 360 lines with that strokeWeight and the jittery motion will probably look like a bunch of lines hard to count, so I thought, why split hairs? :P

Maybe the creature will look pretty similar with about 60 radii which means 30 diameters.

Now to explain a bit of the trig functions used for this.
The main thing is the 'polar to cartesian' coordinates conversion:

Polar would be something like:

"I am moving on a circle to a direction described by an angle (much like one handle of a clock) and radius (distance from centre)."

and Cartesian

"I'm moving based on two axes (horizontal/X and vertical/Y), kind of like the streets of Manhattan, but I cheat and also move diagonally through walls."

If that makes any sense... :)
Anyway, you convert the angle and radius pair to the x and y pair using the formula:

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

For each line:

angle = hairAngle
radius = hairLength

So the line() with *x + (hairCos * -hairLength)* looks a bit like this:

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

Similar for y, but using cos, so this puts the first point of the line in the opposite direct (-hairLength) of the angle moving from the centre (which is the Creature's x) and the second is 'diagonal'. Imagine drawing 'diagonals' (from (-x,-y) to (+x,+y)), but you also rotate these.

Update

Apparently copy/pasting this code works in javascript too (best viewed in Chromium/Chrome). You can also run it right here:

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>

Creatures JS sketch preview

内心荒芜 2024-10-12 11:22:39

您可以使用frameRate(fps)函数。它的作用是指定每秒显示的帧数。然而,如果处理器的速度不够快,无法维持指定的速率,则无法实现。例如,函数调用 frameRate(30) 将尝试每秒刷新 30 次。建议在 setup() 中设置帧速率。

请记住,使用 draw() 而不指定帧速率,默认情况下它将以 60 fps 运行。

You could use the frameRate(fps)function. What it does is, it specifies the number of frames to be displayed every second. However, If the processor is not fast enough to maintain the specified rate, it will not be achieved. For example, the function call frameRate(30) will attempt to refresh 30 times a second. It is recommended to set the frame rate within setup().

Remember, using draw() without specifying the frame rate, by default it will run at 60 fps.

小苏打饼 2024-10-12 11:22:39

好吧,有一个很好的旧随机暂停法。这是“穷人的侧写师”。

多拍几次就可以了。这将准确地告诉您什么花费了最多的时间。如果你能做得更快,这些就是你应该看到的东西。
它将以增加的帧速率显示。

Well, there's the good old random-pause method. It's the "poor man's profiler".

Just snapshot it a few times. That will show you exactly what's taking the most time. Those are the things you should see if you can make faster.
It will show up in increased framerate.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文