Optimization! (warning: horrible nasty code, enter at your own risk)
in
Programming Questions
•
2 years ago
I made a game! have a
link
Anyway, the framerate is less than I'd like, so I'm looking to optimize it some. Here's an overview of things I think could be done, but am unsure about:
-making my looping more efficient, definitely
-arraylists?
-little things like multiplication over division?
-some methods are faster than others but do the same thing?
-stupid stuff that only needs to be done once?
The reason I'm passing the PImages whenever I construct something is because I read somewhere it's faster to do that than to load them in the constructor. Is this true?
Anyway, the framerate is less than I'd like, so I'm looking to optimize it some. Here's an overview of things I think could be done, but am unsure about:
-making my looping more efficient, definitely
-arraylists?
-little things like multiplication over division?
-some methods are faster than others but do the same thing?
-stupid stuff that only needs to be done once?
The reason I'm passing the PImages whenever I construct something is because I read somewhere it's faster to do that than to load them in the constructor. Is this true?
- import ddf.minim.*;
boolean left; // booleans for if those keys are pressed
boolean right; // actually WASD, not arrows
boolean up;
boolean down;
boolean shoot; // whether spacebar is pushed
boolean firstTime; // display the welcome screen or not
boolean paused; // display the pause screen or not
boolean dead; // display the death sequence or not
float x; // x-coordinate of the player
float y; // y-coordinate of the player
float xvel; // x-velocity of the player
float yvel; // y-velocity of the player
float step; // acceleration when (up) is true
float angle; // current angle of the player
float zoomCounter; // used for the zoom in the cutscene
PImage sprite; // player
PImage asteroid; // asteroids
PImage backing; // background
PImage oneUpSprite; // extra lives
PImage explosion; // 5x5 grid that I loop through for the explosions
PImage enemy; // enemy ship
PImage flame; // jets on the back of the player
PFont f; // font for score, lives, etc
int shootCounter; // timing for bursts
int flash; // timing for the little flash when the player is hit
int lives; // how many lives the player has
int invincible; // how long the player is invincible after being hit
int enemiesKilled; // how many enemies have been killed
int numMissed; // how many bullets didn't hit something (for accuracy calculation)
int numShot; // how many bullets have been shot by the player (for accuracy)
long score;
long timeSinceLastSpawn; // timing for enemies so you don't sit there for five minutes randomly
ArrayList shots; // list of all the bullets on the screen
ArrayList asteroids; // all the asteroids
ArrayList enemies; // all the enemies
ArrayList enemyShots; // all the enemy shots
ArrayList oneUps; // all the extra lives
ArrayList booms; // all the explosions
HScrollbar speedBar; // for setting speed, yes I stole this class from someone
Jet jet1; // left flame
Jet jet2; // right flame
Boss boss; // invincible boss
CutScene cutscene; // death movie clip
Boom lastBoom; // the explosion in the movie clip
Minim minim; // for sound :D
AudioSample gun; // also for sound
void setup()
{
size(800,600);
initialize(); // initializes all the vars, loads images, etc
}
void draw()
{
int asdf;
if(step < 0) asdf = -1;
else asdf = 1;
step = asdf * speedBar.getPos() / 80;
if(firstTime) // welcome screen
{
background(100);
fill(200);
textAlign(CENTER);
text("welcome",width/2,height/2);
text("press a key to begin",width/2,height/2 + 20);
}
else // not firstTime
{
if(lives == -1 && dead == true)
{
delay(500);
lives = 0; // go to cutscene!
}
if(lives == 0 && dead == false)
{
stroke(100,100,100);
noFill();
ellipse(x,y,sprite.width,sprite.height);
dead = true;
lives = -1; // shows that it's time to go to the if statement above
}
if(lives > 0)
{
if(!paused && focused)
{
background(backing);
if(random(500) < 1) // randomly spawn extra lives
{
oneUps.add(new OneUp((int)random(width-oneUpSprite.width), (int)random(height-oneUpSprite.height),speedBar.getPos()));
}
//randomly spawn enemies
if(random(1000) - random(1)*enemiesKilled < 1 && enemiesKilled < 20 || millis() - timeSinceLastSpawn > 5000)
{
timeSinceLastSpawn = millis();
int foo = (int)random(4);
Enemy e = new Enemy(0,0,enemy);
switch(foo)
{
case(0):
e.setX((int)random(width));
e.setY(0);
break;
case(1):
e.setX((int)random(width));
e.setY(height);
break;
case(2):
e.setY((int)random(height));
e.setX(0);
break;
case(3):
e.setY((int)random(height));
e.setX(width);
break;
}
enemies.add(e);
}
if(enemiesKilled >= 20 && boss == null) // if you've killed 20 enemies, it's boss-time, but only one boss
{
boss = new Boss(width/2,height/2,enemy);
enemies.add(boss);
}
for(int i =0;i<oneUps.size();i++)
{
OneUp tempLife = (OneUp)oneUps.get(i);
if(!tempLife.isAlive()) //the lifetime of the extra lives, they don't last forever
oneUps.remove(i);
//collision detection with player
if(sqrt(sq(x-(tempLife.getX()+oneUpSprite.height/2)) + sq(y-(tempLife.getY() + oneUpSprite.width/2))) < sprite.height/2 + 3)
{
if(i<oneUps.size())
{
oneUps.remove(i);
lives++;
}
}
tempLife.act(); // display and increment how long it's been alive
}
if(up) // move forward
{
yvel+= -.05 * step * sin(angle);
xvel+= -.05 * step * cos(angle);
}
if(left) // rotate counter-clockwise
{
angle -= speedBar.getPos()/4000;
}
if(right) // rotate clockwise
{
angle += speedBar.getPos()/4000;
}
if(down) // brake
{
xvel*=.93;
yvel*=.93;
}
if(xvel > 3) xvel = 3; //cap the max speed so it doesn't go out of control
if(yvel > 3) yvel = 3;
if(xvel< -3) xvel = -3;
if(yvel< -3) yvel = -3;
x+=xvel; // move the player
y+=yvel;
stroke(100);
fill(100);
for(int j = 0;j<asteroids.size();j++)
{
Asteroid a = (Asteroid)asteroids.get(j);
a.setVelocity(speedBar.getPos() / 100);
// if it's off the screen, spawn a new one
if(a.getY() >= height || a.getY() <= 0-a.getHeight() || a.getX() >= width || a.getX() <= 0-getWidth())
{
int foo = (int)random(4);
switch(foo) // just randomly setting its attributes
{
case(0):
a.setX((int)random(width));
a.setY(0);
a.setAngle(random(PI));
break;
case(1):
a.setX((int)random(width));
a.setY(height);
a.setAngle(random(PI)+PI);
break;
case(2):
a.setY((int)random(height));
a.setX(0);
a.setAngle(random(PI)-PI/2);
break;
case(3):
a.setY((int)random(height));
a.setX(width);
a.setAngle(random(PI)+PI/2);
break;
}
}
a.move();
//if the player hits an asteroid
if(sqrt(sq(x-(a.getX()+asteroid.height/2)) + sq(y-(a.getY() + asteroid.width/2))) < sprite.height/2)
{
if(invincible <= 0) // and he's not invincible from the last time
{
lives--;
booms.add(new Boom(a.getX() + asteroid.width/2, a.getY()+asteroid.height/2, explosion));
invincible = 100;
flash = 10;
}
}
}
for(int i = 0;i<booms.size();i++)
{
Boom expl0de = (Boom) booms.get(i); // sorry for the poor names :P
if(expl0de.isAlive()) // isAlive returns whether it's run out of frames to use for the explosion image
{
expl0de.act(); // go to the next frame
}
else
{
booms.remove(i); // it's done exploding, so get rid of it
}
}
if(shoot && shootCounter > 10) // spacebar is pressed and time since last burst is sufficient
{
gun.trigger(); // sound
for(int i = 0;i<5;i++) //make five new bullets go in random directions within a range
{
Bullet bob = new Bullet(x+random(-1,1),y+random(-1,1),angle+random(-.2,.2),color(250,250,0));
bob.setSpeedConst(2);
shots.add(bob);
numShot++;
shootCounter = 0;
}
}
shootCounter++; // for burst timing
for(int i = 0;i<shots.size();i++)
{
Bullet bill = (Bullet) shots.get(i);
bill.setVelocity(speedBar.getPos() * bill.getSpeedConst()/ 100); // keep it in tune with the speed control
bill.move();
if(bill.getX() < 0 || bill.getX() > width ||
bill.getY() < 0 || bill.getY() > height) // off the screen
{
shots.remove(i);
numMissed++;
}
for(int j = 0;j<asteroids.size();j++)
{
Asteroid a = (Asteroid)asteroids.get(j); // shot collides with asteroid
if(abs(bill.getX()-(a.getX()+asteroid.width/2)) < 10 && abs(bill.getY() - (a.getY()+asteroid.height/2)) < 10)
{
if(i<shots.size())shots.remove(i);
score +=5; // +5 points :D
int foo = (int)random(4);
booms.add(new Boom(a.getX() + asteroid.width/2, a.getY()+asteroid.height/2, explosion));
switch(foo)//spawn a new asteroid randomly
{
case(0):
a.setX((int)random(width));
a.setY(0);
a.setAngle(random(PI));
break;
case(1):
a.setX((int)random(width));
a.setY(height);
a.setAngle(random(PI)+PI);
break;
case(2):
a.setY((int)random(height));
a.setX(0);
a.setAngle(random(PI)-PI/2);
break;
case(3):
a.setY((int)random(height));
a.setX(width);
a.setAngle(random(PI)+PI/2);
break;
}
}
}
for(int j=0;j<enemies.size();j++)
{
Enemy e = (Enemy)enemies.get(j); // if a player's shot hits an enemy
if(abs(e.getX() - bill.getX()) < 23 && abs(e.getY() - bill.getY()) < 30)
{
if(i<shots.size())shots.remove(i);
enemies.remove(j);
e.setLife(e.getLife() -1);
if(e.getLife() > 0)
{
enemies.add(e);
}
else
{
enemiesKilled++;
score += 100; // +100 points :D
}
booms.add(new Boom((int)bill.getX(), (int)bill.getY(), explosion));
}
}
}
for(int i = 0;i<enemyShots.size();i++)
{
Bullet bill = (Bullet) enemyShots.get(i);
bill.setVelocity(speedBar.getPos() * bill.getSpeedConst()/ 100); // speed of bullet
bill.move();
if(bill.getX() < 0 || bill.getX() > width || // off the screen
bill.getY() < 0 || bill.getY() > height)
{
enemyShots.remove(i);
}
for(int j = 0;j<asteroids.size();j++)
{
Asteroid a = (Asteroid)asteroids.get(j); // enemy shot hits an asteroid
if(abs(bill.getX()-(a.getX()+asteroid.width/2)) < 10 && abs(bill.getY() - (a.getY()+asteroid.height/2)) < 10)
{
if(i<enemyShots.size())enemyShots.remove(i);
int foo = (int)random(4);
booms.add(new Boom(a.getX() + asteroid.width/2, a.getY()+asteroid.height/2, explosion));
switch(foo)
{
case(0):
a.setX((int)random(width));
a.setY(0);
a.setAngle(random(PI));
break;
case(1):
a.setX((int)random(width));
a.setY(height);
a.setAngle(random(PI)+PI);
break;
case(2):
a.setY((int)random(height));
a.setX(0);
a.setAngle(random(PI)-PI/2);
break;
case(3):
a.setY((int)random(height));
a.setX(width);
a.setAngle(random(PI)+PI/2);
break;
}
}
}
// enemy shot hits player
if(sqrt(sq(x-bill.getX()) + sq(y-bill.getY())) < sprite.height/2)
{
if(invincible <= 0)
{
lives--;
if(i<enemyShots.size())enemyShots.remove(i); // I was getting some weird errors and this fixed it... whatever
booms.add(new Boom((int)bill.getX(), (int)bill.getY(), explosion));
invincible = 100;
flash = 10;
}
}
}
if(invincible > 0) //makes everything translucent after the player is hit
{
invincible--;
tint(255,128);
stroke(100,100,100);
noFill();
ellipse(x,y,sprite.width,sprite.height);
}
else
{
tint(255,255); // no tint
}
if(flash>0) // this does the flash part of it after the player is hit
{
fill(0,flash*10);
rectMode(CORNER);
rect(0,0,width,height);
flash--;
}
textFont(f);
fill(255);
textAlign(RIGHT);
text(lives + " lives",width-3,20); // displays stats in upper right
text(score + " points",width-3,50);
text((int)frameRate + " fps", width-3,80);
translate(x,y); // PITA code that displays the ship at the correct angle
rotate(angle);
x = constrain(x,0,width); // keep the ship on the screen
y = constrain(y,0,height);
image(jet1.act(left||up),-2*sprite.width/3,sprite.height/3-flame.height/20); // displays the jets
image(jet2.act(right||up),-2*sprite.width/3,-sprite.height/3-flame.height/20);
image(sprite,-sprite.width/2,-sprite.height/2);
rotate(-angle);
translate(-x,-y);
for(int i = 0; i < enemies.size();i++) // displays all the enemies
{
Enemy tempEnemy = (Enemy) enemies.get(i);
translate(tempEnemy.getX(), tempEnemy.getY());
rotate(tempEnemy.getAngle());
image(enemy, -enemy.width/2, -enemy.height/2);
rotate(-tempEnemy.getAngle());
translate(-tempEnemy.getX(), -tempEnemy.getY());
Bullet tempBullet = tempEnemy.act((int)x,(int)y); // enemies shoot at the player
if(tempBullet!=null) enemyShots.add(tempBullet); // returns null if it's not time yet
}
}
else // not paused and/or focused
{ //displays the pause screen
if(!focused) paused = true;
background(0);
textFont(f);
fill(255);
textAlign(CENTER);
text("Press P to resume",width/2,100);
text("Speed:",width/2,2*height/3 - 20);
text(enemiesKilled + " enemies killed", width/2,height/2);
speedBar.update();
speedBar.display();
}
}
else if(lives ==0)
{
if(!cutscene.timeToQuit())
{
zoomCounter +=.001;
tint(255,255);
translate(width/2 + zoomCounter * 100,height/2 - zoomCounter * 80);
scale(1 + zoomCounter);
translate(-width/2,-height/2);
if(cutscene.isAlive()) cutscene.play();
else if(lastBoom.isAlive()) lastBoom.act();
else cutscene.empty();
}
else // cutscene is over
{
tint(255,255);
background(0);
booms.add(new Boom((int)random(width), (int)random(height),explosion)); // random explosions just for kicks
for(int i = 0;i<booms.size();i++)
{
Boom expl0de = (Boom) booms.get(i);
if(expl0de.isAlive())
{
expl0de.act();
}
else
{
booms.remove(i);
}
}
textFont(f);
fill(0);
textAlign(CENTER);
rect(width/3,height/4,width/3,height/2);
fill(255);
text("GAME OVER", width/2,height/3);
text(enemiesKilled + " enemies killed",width/2,5*height/12);
text(score + " points",width/2,height/2);
text(numShot +" shots fired", width/2, 7*height/12);
text((int)((1.0 - (double)numMissed / numShot)*100) + "% accuracy", width/2, 2*height/3);
}
}
}
}
void keyTyped()
{
firstTime = false;
switch(key)
{
case('w'):
up = true;
step = -6;
break;
case('s'):
down = true;
step = 6;
break;
case('a'):
left = true;
break;
case('d'):
right = true;
break;
case('r'):
loop();
initialize();
break;
case('p'):
paused = !paused;
break;
case(32):
shoot = true;
break;
}
}
void keyReleased()
{
switch(key)
{
case('w'):
up = false;
break;
case('s'):
down = false;
break;
case('a'):
left = false;
break;
case('d'):
right = false;
break;
case(32):
shoot = false;
break;
}
}
void initialize()
{
left = false; // no keys pressed at the beginning
right = false;
up = false;
down = false;
firstTime = true;
paused = false;
angle = radians(270);
speedBar = new HScrollbar(width/2-100, 2*height/3,200,20,16);
x = width/2;
y = height/2;
xvel = 0;
yvel = 0;
step = 0;
sprite = loadImage("spaceship1.gif");
backing = loadImage("space.jpg");
asteroid = loadImage("asteroid.gif");
oneUpSprite = loadImage("1up.gif");
explosion = loadImage("explosion17.png");
enemy = loadImage("enemy.png");
backing.resize(width, height);
f = loadFont("SansSerif-12.vlw");
asteroids = new ArrayList();
for(int i = 0;i<3;i++) // throws random asteroids for starting
{
asteroids.add(new Asteroid((int)random(width),(int)random(height),random(5),asteroid));
}
lives = 10;
score = 0;
invincible = 200;
flash = 3;
shoot = false;
shots = new ArrayList();
oneUps = new ArrayList();
enemies = new ArrayList();
enemyShots = new ArrayList();
enemies.add(new Enemy(100,100,enemy));
booms = new ArrayList();
dead = false;
flame = loadImage("flames.gif");
jet1 = new Jet(flame);
jet2 = new Jet(flame);
enemiesKilled = 0;
numMissed = 0;
numShot = 0;
shootCounter = 0;
cutscene = new CutScene();
lastBoom = new Boom(295,408,explosion);
zoomCounter = 0;
timeSinceLastSpawn = millis();
minim = new Minim(this);
gun = minim.loadSample("lol.wav");
}
1