Display an Image for 5 Seconds Only Flashing

I’m creating a basic catcher-style game that catches balls of varying sizes and colors. I have a “game over” image that I’d like to display for 5 seconds before restarting the game. Right now, the image flashes but the game immediately goes back to start. I’ve created a timer “endingtimer” for 750 millis (5 seconds). I’ve added tons of notes to clarify what I’m trying to do with each step. Any ideas on what I’m doing wrong?

Hole hole; //one black hole catcher
Timer timer; //one timer
Planet[] planets; //an array of planets
Score score; //one scoreboard
int totalPlanets = 0; //total planets
int caughtNum; //# of planets caught
EndingTimer endingtimer; //timer for game ending screen
boolean gameOver; //tracker for game over
boolean gameStarted; //tracker for game started

//initialize images
PImage startScreenImage;
PImage backgroundImage;
PImage endingImage;

void setup() {
  fullScreen();
  smooth();
  hole = new Hole(32); //create black hole w/height radius of 32
  planets = new Planet[1000]; //create 1000 spots in array
  timer = new Timer(300); //create timer that goes off every 2 seconds
  endingtimer = new EndingTimer(750); //create timer for 5 seconds
  score = new Score(width-100, 100); //create score board w/x & y location values
  timer.start(); //start timer
  gameOver = false; //set tracker status
  gameStarted = false; //set tracker status
  
  //load background images
  startScreenImage = loadImage("grav_trap_start.png");
  backgroundImage = loadImage("grav_trap_background.png");
  endingImage = loadImage("grav_trap_ending.png");
}

void draw() {
  //if game has not started, display intro screen 
  if (!gameStarted) {
    image(startScreenImage,0,0, width, height);
  //if game is over, display ending screen for 5 seconds
  } else if (gameOver) {
    endingtimer.start(); //start ending screen timer
    image(endingImage,0,0, width, height); //display ending image
    if (endingtimer.isFinished()) {
    restart(); //restart game after 5 seconds
  }
  
  //start game
  } else {
    //display background image
    image(backgroundImage,0,0);
    //set black hole location & display
    hole.setLocation(mouseX, mouseY);
    hole.display();
  
    //initialize one planet if 2 seconds have passed
    if (timer.isFinished()) {
    planets[totalPlanets] = new Planet();
    //increment total planets
    totalPlanets++;
    //if hit end of array
    if (totalPlanets >= planets.length) {
    totalPlanets = 0; //start over
    }
    timer.start();
    }
    
    //move and display all planets
    for (int i = 0; i < totalPlanets; i++) {
      planets[i].move();
      planets[i].display();
      //check for planet and black hole intersection
      if (hole.intersect(planets[i])) {
        planets[i].caught();
        caughtNum = caughtNum + 1; //increment score
      }
    }
    //if player catches 30, game over
    if (caughtNum == 30) {
      gameOver = true;
    }
    //display score 
    score.display(caughtNum);
  }    
}

void restart() {
  caughtNum = 0;
  gameStarted = false;
  gameOver = false;
}

//start game
void keyPressed() {
  if (!gameStarted) gameStarted = true;  
}

class EndingTimer {
  int savedTime;
  int totalTime;
  
  EndingTimer(int tempTotalTime) {
    totalTime = tempTotalTime;
  }
  
  void start() {
    savedTime = millis();
  }
  
  boolean isFinished() {
    int passedTime = millis() - savedTime;
    if (passedTime > totalTime) {
      return true;
    } else {
      return false;
    }
  }
}

class EndingTimer {
  int savedTime;
  int totalTime;
  
  EndingTimer(int tempTotalTime) {
    totalTime = tempTotalTime;
  }
  
  void start() {
    savedTime = millis();
  }
  
  boolean isFinished() {
    int passedTime = millis() - savedTime;
    if (passedTime > totalTime) {
      return true;
    } else {
      return false;
    }
  }
}

class Planet { 
  float x, y; //planet location
  float speed; //planet speed
  float colR = random(1,255); //random color for R value
  float colG = random(1,255); //random color for G value
  float colB = random(1,255); //random color for B value
  float r; //radius
  float caughtNum;
  
  Planet() {
    //constructor
    r = random(8, 70); // assign random radius to planet
    x = random(width); //start planet in random spot
    y = -r*4; //start planet above window
    speed = random(1, 5); //random speed selection 
    fill(colR, colG, colB); //assign color
    caughtNum = 0;
  }
  
  //move the planet down
  void move() {
    y += speed; //increment by speed
 }
 
  //check if planet hits bottom
  boolean reachedBottom() {
    if (y > height + r*4) {
      return true;
    } else {
      return false;
    }
  }
  
  //display planet
  void display() {
    fill(colR, colG, colB);
    noStroke();
    for (int i = 2; i < r; i++) {
      ellipse (x, y, r*2, r*2);
    }
  }
  
  //if planet caught
  void caught() {
    speed = 0; //stop movement 
    y = -1000; //set location off screen
  }
}

class Score {
  PVector loc; //location of scoreboard
  color c; //scoreboard color
  float tempCaught; //# of planets caught
  
  Score() {
    loc = new PVector();
    c = color(0);
  }
  
  //set location of scoreboard
  Score(float x, float y) {
    this();
    loc.x = x;
    loc.y = y;
  }
  
  //display number caught
  void display(int tempCaught) {
    fill(255);
    textSize(64);
    textAlign(CENTER, TOP);
    text(tempCaught, loc.x, loc.y);
  }
}

class Timer {
  int savedTime;
  int totalTime;
  
  Timer(int tempTotalTime) {
    totalTime = tempTotalTime;
  }
  
  void start() {
    savedTime = millis();
  }
  
  boolean isFinished() {
    int passedTime = millis() - savedTime;
    if (passedTime > totalTime) {
      return true;
    } else {
      return false;
    }
  }
}

Your if/else braces are a bit tangled in draw(). Start from the top of the function and very carefully indent the body of each if and else block of code. I think you have things nested differently than you mean to.

Let me suggest that rather than using separate booleans for gameStarted and gameOver, that you create a single integer gameState that can hold more than just 2 values. Let it equal 0 for the intro screen, 1 while the game is playing, and 2 for the end screen. Even cleaner, you can create an enum:

enum GameState {
  INTRO, PLAYING, ENDSCREEN
}
GameState gameState = GameState.INTRO;

and then in draw():

void draw() {
  if( gameState == GameState.INTRO ) {
    //show intro screen

  } else if( gameState == GameState.ENDSCREEN ) {
    // show end screen
    if( /* endscreen timer done */ )
      gameState = GameState.INTRO;

  } else {   // gameState is GameState.PLAYING

    // play the game

    if( /* whatever makes the game end */ ) {
      // start end screen timer
      gameState == GameState.ENDSCREEN;
    }
  }
}

void keyPressed() {
  if( gameState == GameState.INTRO )
    gameState = GameState.PLAYING;
}
3 Likes

Thank you for the suggestion. Here is what I came up with… but now it won’t move past the first screen. I’m super new to Processing (and coding in general), so any ideas you have would be welcome!

/*The logic for the catcher part of the game is inspired by Learning Processing by
Daniel Shiffman, pages 168-189. The scorekeeping & image logic is taken from
the example videos by Professor Stone.
*/

Hole hole; //one black hole catcher
Timer timer; //one timer
Planet[] planets; //an array of planets
Score score; //one scoreboard
int totalPlanets = 0; //total planets
int caughtNum; //# of planets caught
EndingTimer endingtimer; //timer for game ending screen
PImage startScreenImage;
PImage backgroundImage;
PImage endingImage;
GameState gameState = GameState.INTRO;

void setup() {
  fullScreen();
  smooth();
  hole = new Hole(32); //create black hole w/height radius of 32
  planets = new Planet[1000]; //create 1000 spots in array
  timer = new Timer(300); //create timer that goes off every 2 seconds
  endingtimer = new EndingTimer(750); //create timer for 5 seconds
  score = new Score(width-100, 100); //create score board w/x & y location values
  timer.start(); //start timer
  //load background images
  startScreenImage = loadImage("grav_trap_start.png");
  backgroundImage = loadImage("grav_trap_background.png");
  endingImage = loadImage("grav_trap_ending.png");
}

enum GameState {
  INTRO, PLAYING, ENDSCREEN
}

void draw() {
  if (gameState == GameState.INTRO) {
    image(startScreenImage,0,0, width, height);
  } else if (gameState == GameState.ENDSCREEN) {
    image(endingImage,0,0, width, height);
      if (endingtimer.isFinished()) {
        gameState = GameState.INTRO;
      } else {
        image(backgroundImage,0,0);
        //set black hole location & display
        hole.setLocation(mouseX, mouseY);
        hole.display();
      
        //initialize one planet if 2 seconds have passed
        if (timer.isFinished()) {
        planets[totalPlanets] = new Planet();
        //increment total planets
        totalPlanets++;
        //if hit end of array
        if (totalPlanets >= planets.length) {
        totalPlanets = 0; //start over
        }
        timer.start();
        }
        
        //move and display all planets
        for (int i = 0; i < totalPlanets; i++) {
          planets[i].move();
          planets[i].display();
          //check for planet and black hole intersection
          if (hole.intersect(planets[i])) {
            planets[i].caught();
            caughtNum = caughtNum + 1; //increment score
          }
        }
        
        //display score 
        score.display(caughtNum);
        
        //if player catches 30, game over
        if (caughtNum == 30) {
            endingtimer.start();
            gameState = GameState.ENDSCREEN;
        }
      }   
   }
}

//start game
void keyPressed() {
  if (gameState == GameState.INTRO)
    gameState = GameState.PLAYING;
}

class EndingTimer {
  int savedTime;
  int totalTime;
  
  EndingTimer(int tempTotalTime) {
    totalTime = tempTotalTime;
  }
  
  void start() {
    savedTime = millis();
  }
  
  boolean isFinished() {
    int passedTime = millis() - savedTime;
    if (passedTime > totalTime) {
      return true;
    } else {
      return false;
    }
  }
}

class Hole {
  float r; //size
  color c; //color
  float x, y; //location
  
  //constructor
  Hole (float tempR) {
    r = tempR;
    c = color(0);
    x = 0;
    y = 0;
    }
  
  void setLocation (float tempX, float tempY) {
    x = tempX;
    y = tempY;
    }
    
  void display() {
    //display black hole shaped catcher
    fill(c);
    ellipse(x, y, r*3, r );
  }
  //check to see if planet and black hole intersect  
  boolean intersect(Planet p) {
    //calculate distance
    float distance = dist(x, y, p.x, p.y);
    //compare distance to sum of radii
    if (distance < r + p.r) {
      return true;
    } else {
      return false;
    }
  }
}

class Planet { 
  float x, y; //planet location
  float speed; //planet speed
  float colR = random(1,255); //random color for R value
  float colG = random(1,255); //random color for G value
  float colB = random(1,255); //random color for B value
  float r; //radius
  float caughtNum;
  
  Planet() {
    //constructor
    r = random(8, 70); // assign random radius to planet
    x = random(width); //start planet in random spot
    y = -r*4; //start planet above window
    speed = random(1, 5); //random speed selection 
    fill(colR, colG, colB); //assign color
    caughtNum = 0;
  }
  
  //move the planet down
  void move() {
    y += speed; //increment by speed
 }
 
  //check if planet hits bottom
  boolean reachedBottom() {
    if (y > height + r*4) {
      return true;
    } else {
      return false;
    }
  }
  
  //display planet
  void display() {
    fill(colR, colG, colB);
    noStroke();
    for (int i = 2; i < r; i++) {
      ellipse (x, y, r*2, r*2);
    }
  }
  
  //if planet caught
  void caught() {
    speed = 0; //stop movement 
    y = -1000; //set location off screen
  }
}

class Score {
  PVector loc; //location of scoreboard
  color c; //scoreboard color
  float tempCaught; //# of planets caught
  
  Score() {
    loc = new PVector();
    c = color(0);
  }
  
  //set location of scoreboard
  Score(float x, float y) {
    this();
    loc.x = x;
    loc.y = y;
  }
  
  //display number caught
  void display(int tempCaught) {
    fill(255);
    textSize(64);
    textAlign(CENTER, TOP);
    text(tempCaught, loc.x, loc.y);
  }
}

class Timer {
  int savedTime;
  int totalTime;
  
  Timer(int tempTotalTime) {
    totalTime = tempTotalTime;
  }
  
  void start() {
    savedTime = millis();
  }
  
  boolean isFinished() {
    int passedTime = millis() - savedTime;
    if (passedTime > totalTime) {
      return true;
    } else {
      return false;
    }
  }
}

You still have your if/else blocks tangled. I presume what you meant to have is this:

void draw() {
  if (gameState == GameState.INTRO) {
    image(startScreenImage,0,0, width, height);

  } else if (gameState == GameState.ENDSCREEN) {
    image(endingImage,0,0, width, height);
    if (endingtimer.isFinished()) {
      gameState = GameState.INTRO;
    }

  } else {   // gameState == GameState.PLAYING
    image(backgroundImage,0,0);
    //set black hole location & display
    hole.setLocation(mouseX, mouseY);

It might help to make draw() simpler by moving all of the game update code into its own function:

void draw() {
  if (gameState == GameState.INTRO) {
    image(startScreenImage,0,0, width, height);

  } else if (gameState == GameState.ENDSCREEN) {
    image(endingImage,0,0, width, height);
    if (endingtimer.isFinished()) {
      gameState = GameState.INTRO;
    }

  } else {   // gameState == GameState.PLAYING
    updateGame();
  }
}

void updateGame() {
  image(backgroundImage,0,0);
  //set black hole location & display
  hole.setLocation(mouseX, mouseY);
  hole.display();

  // and so on
}

Gosh, that one bracket out of the right spot and the whole thing doesn’t work! I moved the gameplay code to its own function, and that really helped me to see it more easily. Thank you so much for your help!

1 Like