optimization - Processing: How can I improve the framerate in my program? -
so i've been working in processing few weeks now, and, though i'm not experienced in programming, have moved on more complex projects. i'm programming evolution simulator, spawns creatures random properties.
eventually, i'll add reproduction, of creatures sort of float around screen, , follow mouse somewhat. interacts sound line in, commented parts out can viewed on canvas, shouldn't change question, thought point out.
as of now, framerate far less ideal me, , lowers more creatures spawned. making fundamental mistake, or running many functions per frame?
here's source code, , can play in 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 = 0; < 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 = 0; <= 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(); } } }
right, suspected, unnecessary pushmatrix()
, popmatrix()
calls , large amount of lines seemed main culprits, still, there lot of redundant code.
i refactored code in cleaner manner , seems run fine. here 'improved' version:
int maxcreatures = 75; int numcreatures = 0; int spawnnthframe = 50;//spawn 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 = 0; < numcreatures; i++) creatures[i].update(); }
and creature class:
class creature{ int x,y,cxinc,cyinc;//if x,y ints, increments 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 each piece = 360/number of hair lines float hairangle,hairlength,haircos,hairsin; for(int = 0; < 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, explanations.
first, separated variables related 1 creature 'global' ones determine how sketch runs (how many creatures spawned, etc.).
this makes main code 25 lines long , altogether bit below 100 lines less half of original.
the first part doesn't special. in draw() function, instead of creating creature every frame, draw 1 every nth frame using spawnnthframe variable, made easy see state of creature made slow. if set small number 2 variable should spawn lot of creatures per frame.
the creature class has properties original code stored in arrays.
instead of doing
pushmatrix(); translate(); ellipse(); rotate() ellipse() popmatrix();
i draw ellipses @ x,y. little hint on rotations. i've noticed increments of 90 degrees. processing has nice constants 90,180,360 degrees in radians: half_pi, pi, two_pi can handy sometimes.
now 'hairy' situation, here's commented out myself:
//if(i == 1) for(int j = 0; j <= 360; j+=70) , 360/70 5, if (i == 2) , 12 hair //if = 3-> 360 lines ? need many lines, thick ? how 30 ? 5*12=60, if draw lines through centre, not centre, can away half lines
so there 3 loops drawing lines, each having different increments. there either 360/70 lines, 360/30 lines , 360 lines. 5,12 , 360 lines. 5,12 lines, kind of halved drawing 'diameter' lines across centre opposed 'radius' lines centre.
here's mean,
also think 360 lines strokeweight , jittery motion bunch of lines hard count, thought, why split hairs? :p
maybe creature pretty similar 60 radii means 30 diameters.
now explain bit of trig functions used this. main thing 'polar cartesian' coordinates conversion:
polar like:
"i moving on circle direction described angle (much 1 handle of clock) , radius (distance centre)."
and cartesian
"i'm moving based on 2 axes (horizontal/x , vertical/y), kind of streets of manhattan, cheat , move diagonally through walls."
if makes sense... :) anyway, convert angle , radius pair x , y pair using formula:
x = cos(angle) * radius y = sin(angle) * radius
for each line:
angle = hairangle radius = hairlength
so line() *x + (haircos * -hairlength)* looks bit this:
x + (haircos * -hairlength) = move x , there move hairlength left(-) current angle (haircos)
similar y, using cos, puts first point of line in opposite direct (-hairlength) of angle moving centre (which creature's x) , second 'diagonal'. imagine drawing 'diagonals' (from (-x,-y) (+x,+y)), rotate these.
update
apparently copy/pasting code works in javascript (best viewed in chromium/chrome). can run right here:
var maxcreatures = 75; var numcreatures = 0; var spawnnthframe = 50;//spawn 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 = 0; < 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 each piece = 360/number of hair lines var hairangle,hairlength,haircos,hairsin; for(var = 0; < 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>
Comments
Post a Comment