Brick Game Timer Question

I am trying to make a timer that keeps the “GAME OVER” text on the screen after a few seconds before the game resets. Right now I have a timer more or less copied of the processing forum and I can’t figure out how it works. Once I added the timer the ball spawns in the wrong spot and the “GAME OVER” text only works after a few seconds and never on the second run through. I’m not really sure what to do and any help is appreciated. Below is the game code and under that is the timer code:

float ballx;
float bally;

float ballr = 20;

float xspeed = 7;
float yspeed = 4;

float recty = 750;
float rectw = 150;
float recth = 40;

Timer timer;


void setup() {
  size(800,800);
  timer = new Timer(5000);
  timer.start();
  ballx = width*0.5;
  bally = height*0.8;
 
 
}
   

void draw() {
  background(0);
  //ball
  fill(28,200,255);
  ellipse(ballx,bally,40,40);
  ballx=ballx+xspeed;
  bally=bally+yspeed;
  
  fill(255);
  rectMode(CENTER);
  rect(mouseX, recty, rectw, recth, 30);
  
  //boundaries

 if (ballx>width){
    xspeed=-random(10,12);
  }
  if (ballx<0){
    xspeed=random(10,12);
  }
  
  if (bally<0){
    yspeed=random(6,8);
  }
  
  
  if (bally-ballr/2>height) {
    textSize(130);
    text("GAME OVER", 70, 200);
    
    if (timer.isFinished()) {
    reset();
    }
  } else if (ballx>mouseX-rectw/2 && 
    ballx<mouseX+rectw/2 &&
    bally+ballr/2>recty-23 ) {
    yspeed = -random(8,10);
    xspeed = random(-12,14);
  }
}

void reset() {

  ballx=400;
  bally=200;

  xspeed = 7;
  yspeed = 4;
}

 Timer(int tempTotalTime) {
    totalTime = tempTotalTime;
  }
  
   void start() {
    
    savedTime = millis();
  }

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

Hi @newprogrammer12,

To understand better how it works, maybe start with a simpler example (without Java classes).

Displaying a timer implies using time. In Processing we can get the current time since the beginning of the program in milliseconds with the millis() function.

Let’s look at the following program:

// Starts at the beginning of the program
int timerStart = 0;
int duration = 1000;

void draw() {
  // Time spent since the beginning of the timer
  int timeSinceStart = millis() - timerStart;

  if (timeSinceStart <= duration) {
    println(timeSinceStart);
  } else {
    println("Timer ends");
    noLoop();
  }
}

It will display the time in milliseconds since the beginning of the program and stops when the duration is over.

Now you need a way to trigger the timer and run it again. Let’s do that by resetting the timerStart to the current time using millis():

int timerStart = 0;
int duration = 1000;

void mousePressed() {
  // Set the start of the timer to the click time
  timerStart = millis();
}

void setup() {
  size(200, 200);
}

void draw() {
  background(255);

  int timeSinceStart = millis() - timerStart;

  textAlign(CENTER, CENTER);
  fill(0);

  if (timeSinceStart <= duration) {
    text(timeSinceStart, width / 2, height / 2);
  } else {
    text("TIMER NOT ACTIVE, CLICK", width / 2, height / 2);
  }
}

Now the issue is that it will start at the beginning because the start time is 0. We can wrap this code into a proper class and control the start (same as the non complete example you sent).

class Timer {
  int duration;
  int savedTime = 0;
  boolean started = false;
  
  Timer(int duration) {
    this.duration = duration;
  }
  
  void start() {
    started = true;
    savedTime = millis();
  }
  
  boolean isFinished() {
    return started && millis() - savedTime > duration;
  }
}

Timer timer;

void setup() {
  size(200, 200);
  timer = new Timer(4000);
  timer.start();
}

void draw() {
  if (timer.isFinished()) {
    println("TIMER OVER");
    noLoop();
  }
}

Now you should be able to use it properly to display your Game over screen. :wink:

1 Like

@josephh Thank you so much for this response! This is extremely helpful.

2 Likes

@josephh I have one more question. It now works great! However, if I wanted to make it so when I click the game restarts, do you know what I could do?

Glad that it worked!

So you want to restart the game on click and also after the timer is over?

If you have a way to restart your game (reset all the state variables and objects) then you can do the following (in pseudocode):

// The user clicks explicitly so the game restarts
void mousePressed() {
  if (timer.started && !timer.isFinished()) {
    restartGame();
    timer.reset();
  }
}

//...

// In this case the timer is over and the user didn't click
void draw() {
  if (timer.isFinished()) {
    restartGame();
    timer.reset(); // To implement yourself
  }
}
2 Likes

i tried to do a timer reset and something called a Null Pointer Error came up. Not sure what that means. Here is the new code:

float ballx;
float bally;

float ballr = 20;

float xspeed = 7;
float yspeed = 4;

float recty = 750;
float rectw = 150;
float recth = 40;

Timer timer;
int timerStart = 0;
int duration = 1000;

void mousePressed() {
  if (timer.started && !timer.isFinished()) {
    reset();
    timerstop();
}

  size(800,800);
  timer = new Timer(4000);
  timer.start();
  ballx = 400;
  bally = 200;
 
 
}
   

void draw() {
  
  background(0);
  //ball
  fill(28,200,255);
  ellipse(ballx,bally,40,40);
  ballx=ballx+xspeed;
  bally=bally+yspeed;
  
  fill(255);
  rectMode(CENTER);
  rect(mouseX, recty, rectw, recth, 30);
  
  if (timer.isFinished()) {
    reset();
    timerstop(); 
  }
  
  //boundaries

 if (ballx>width){
    xspeed=-random(10,12);
  }
  if (ballx<0){
    xspeed=random(10,12);
  }
  
  if (bally<0){
    yspeed=random(6,8);
  }
  
  
  if (bally-ballr/2>height) {
    textSize(130);
    text("GAME OVER", 70, 200);
    
    //Timer
  int timeSinceStart = millis() - timerStart;

  textAlign(CENTER, CENTER);
  fill(0);

  if (timeSinceStart <= duration) {
    text(timeSinceStart, width / 2, height / 2);
  } else {
    text("TIMER NOT ACTIVE, CLICK", width / 2, height / 2);
  }
   

  if (timeSinceStart <= duration) {
    println(timeSinceStart);
  } else {
    println("Timer ends");
    noLoop();
  }
  if (timer.isFinished()) {
    println("TIMER OVER");
    noLoop();
  }
  if (timer.isFinished()) {
  reset();
  }
  } else if (ballx>mouseX-rectw/2 && 
    ballx<mouseX+rectw/2 &&
    bally+ballr/2>recty-23 ) {
    yspeed = -random(8,10);
    xspeed = random(-12,14);
  }
  
}

void reset() {
  
  ballx=400;
  bally=100;

  xspeed = 7;
  yspeed = 4;
  
  
}

void timerstop() {
  if (mousePressed && !timer.isFinished()) {
    timer = new Timer(4000);
  }
}

Yes if you run it, there’s an error at line 66:

if (timer.isFinished()) {

To explain what the NullPointerException means in Java:

  • You are trying to call the isFinished method on the timer object

  • The timer variable is supposed to be pointing to a Timer class instance in memory but by default it’s value is null and it wasn’t initialized before draw()

  • You can’t call anything on a null value → You get a NullPointerException

Solution:

// The variable is declared but not initialized
// Equivalent to: Timer timer = null;
Timer timer;

void setup() {
  // Initialize it once
  timer = Timer();
}

void draw() {
  // use it here...
}
1 Like

ok the null value problem is fixed. i have written code that looks like it should be making the whole program and timer reset after A. the ball passes passed the bottom boundary and B. the mouse is pressed. However, when i press the mouse after the game over appears, nothing happens. do you know where in this code im going wrong?

float ballx;
float bally;

float ballr = 20;

float xspeed = 7;
float yspeed = 4;

float recty = 750;
float rectw = 150;
float recth = 40;

Timer timer;
int timerStart = 0;
int duration = 1000;

void mousePressed() {
  if (timer.started && !timer.isFinished()) {
    reset();
    timerstop();
}
}
void setup() {
  size(800,800);
  timer = new Timer(4000);
  
  timer.isFinished();
  timer.start();
  ballx = 400;
  bally = 200;
}
 

   

void draw() {
  
  background(0);
  //ball
  fill(28,200,255);
  ellipse(ballx,bally,40,40);
  ballx=ballx+xspeed;
  bally=bally+yspeed;
  
  fill(255);
  rectMode(CENTER);
  rect(mouseX, recty, rectw, recth, 30);
  
  timer = new Timer(4000);
  
 if (timer.isFinished()) {
    reset();
    timerstop(); 
  }
  
  
  //boundaries

 if (ballx>width){
    xspeed=-random(10,12);
  }
  if (ballx<0){
    xspeed=random(10,12);
  }
  
  if (bally<0){
    yspeed=random(6,8);
  }
  
  
  if (bally-ballr/2>height) {
    textSize(130);
    text("GAME OVER", 70, 200);
    
    //Timer
  int timeSinceStart = millis() - timerStart;

  textAlign(CENTER, CENTER);
  fill(0);

  if (timeSinceStart <= duration) {
    text(timeSinceStart, width / 2, height / 2);
  } else {
    text("TIMER NOT ACTIVE, CLICK", width / 2, height / 2);
  }
   

  if (timeSinceStart <= duration) {
    println(timeSinceStart);
  } else {
    println("Timer ends");
    noLoop();
  }
  if (timer.isFinished()) {
    println("TIMER OVER");
    noLoop();
  }
  if (mousePressed && !timer.isFinished()) {
  reset();
  }
  } else if (ballx>mouseX-rectw/2 && 
    ballx<mouseX+rectw/2 &&
    bally+ballr/2>recty-23 ) {
    yspeed = -random(8,10);
    xspeed = random(-12,14);
  }
  
}

void reset() {
  
  ballx=400;
  bally=100;
  
  xspeed = 7;
  yspeed = 4;
  
  timer = new Timer(4000);
}
  


void timerstop() {
  if (mousePressed && !timer.isFinished()) {
    reset();
  }

}

1 Like

Do you really need to check the timer in case of the mouse?

ok i changed it. i put reset(); inside of the void mousePressed. this makes it reset now whenever the mouse is pressed UNLESS the ball has passed the lower boundary which kinda defeats the purpose of it. am i vaguely on the right track? any clues on what im doing wrong? i want to fix this myself if you know what i mean but i keep getting stuck whenever i think ive made a breakthrough.

float ballx;
float bally;

float ballr = 20;

float xspeed = 7;
float yspeed = 4;

float recty = 750;
float rectw = 150;
float recth = 40;

Timer timer;
int timerStart = 0;
int duration = 1000;

void mousePressed() {
  timerStart = millis();
  reset();
}
void setup() {
  size(800,800);
  timer = new Timer(4000);
  timer.start();
  ballx = 400;
  bally = 200;
 
 
}
   

void draw() {
  
  background(0);
  //ball
  fill(28,200,255);
  ellipse(ballx,bally,40,40);
  ballx=ballx+xspeed;
  bally=bally+yspeed;
  
  fill(255);
  rectMode(CENTER);
  rect(mouseX, recty, rectw, recth, 30);
  
 
  
  //boundaries

 if (ballx>width){
    xspeed=-random(18,20);
  }
  if (ballx<0){
    xspeed=random(18,20);
  }
  
  if (bally<0){
    yspeed=random(10,12);
  }
  
  
  if (bally-ballr/2>height) {
    textSize(130);
    text("GAME OVER", 70, 200);
   
    //Timer
  int timeSinceStart = millis() - timerStart;

  textAlign(CENTER, CENTER);
  fill(0);

  if (timeSinceStart <= duration) {
    text(timeSinceStart, width / 2, height / 2);
  } else {
    text("TIMER NOT ACTIVE, CLICK", width / 2, height / 2);
  }
   

  if (timeSinceStart <= duration) {
    println(timeSinceStart);
  } else {
    println("Timer ends");
    noLoop();
  }
  if (timer.isFinished()) {
    println("TIMER OVER");
    noLoop();
  }
  
  if (bally-ballr/2>height && mousePressed) {
       reset();
}
  } else if (ballx>mouseX-rectw/2 && 
    ballx<mouseX+rectw/2 &&
    bally+ballr/2>recty-23 ) {
    yspeed = -random(8,10);
    xspeed = random(-12,14);
  }
  
}

void reset() {
  
  ballx=400;
  bally=100;

  xspeed = 7;
  yspeed = 4;
  
  
}