Changing game states (beginner)

Hello! I am a recent beginner (1 week), and just trying to make a simple game where you need to dodge a car. Currently I have 3 states; state 0: the beginning screen (fully light blue currently), state 1: The actual gameplay and state 2: the end screen. I want to be able to, once I press any button, be able to return to state 0 from state 2, and from there on being able to once again press any button to move into state 1 (from state 0 --> 1 is already implemented). If anyone could help me basically reset the game, that would be awesome. Any general tips (or things that I’m doing wrong) would be greatly appreciated. Thanks for reading :slight_smile:

PFont f;

void setup() {
  size(1920, 1080);
  f = createFont("Times New Roman", 64, true);
  myob4 = new ob(color(#FF0808), 0, 900, 5); //parameters (color, then xpos, ypos and speed)
  myob5 = new ob(color(#FF0808), 0, 900, 4);   // in progress second OB
  myrun = new run(color(#6C00FC), 0, 1000, 3, 0); //runner (last value is yspeed)
  mysun = new sun(color(#FCD700), 0, 300, 3, 1); //sun (color, xpos, ypos, xspeed, yspeed)
  mysun1 = new sun(color(#C1BDB2), 0, 300, 3, 1); //moon
}

int state; 
int START_SCREEN = 0;
int GAME = 1;
int FAIL = 2;
int score = 50;
boolean start = true;
int time = millis();



void draw() {
  if ( state == 0) {
    start = false;
    if (keyPressed) {
      state = 1;
    }
  } else if (state == 1) {
    start = true; 
  } else if (state == 2) {
    if (mouseButton == LEFT) {
      state = 1;
    }
  }
  if (score < -1) {
    state = 2;
  } 
  switch(state) {
  case 0:
    displayStartscreen();
    break;
    //--------------------------
  case 1:
    displayGame();
    break;
    //---------------------
  case 2:
    displayFail();
    break;
    //-----------------
  }
}


ob myob4;
ob myob5;
class ob {
  color c1;
  float xpos1;
  float ypos1;
  float xspeed1;

  //Constructor
  ob (color tempC1, float tempXpos1, float tempYpos1, float tempXspeed1) {
    c1 = tempC1;
    xpos1 = tempXpos1;
    ypos1 = tempYpos1;
    xspeed1 = tempXspeed1;
  }
  void display() {
    noStroke();
    fill(c1);
    rectMode(CENTER);
    rect(xpos1, ypos1, 500, 120);
    fill(0);
    ellipse(xpos1 - 170, ypos1 + 60, 100, 100);
    ellipse(xpos1 + 170, ypos1 + 60, 100, 100);  
    triangle(xpos1 - 140, ypos1 - 60, xpos1 - 70, ypos1 - 110, xpos1 - 70, ypos1 - 60);
  }

  void drive() {
    xpos1 = xpos1 - xspeed1;
    if (xpos1 + 250 < 0) {
      xpos1 = random(1920, 2400);                                  //random spawn distance
      String xposition = "Position of the obstacle is " + xpos1;
      println(xposition);  
      c1 = (color(random(255), random(255), random(255)));
    }
  }
}


//Runner
run myrun;
class run {
  color c2;
  float xpos2;
  float ypos2;
  float xspeed2;
  int yspeed2;

  //Constructor
  run (color tempC2, float tempXpos2, float tempYpos2, float tempXspeed2, int tempYspeed2) {
    c2 = tempC2;
    xpos2 = tempXpos2;
    ypos2 = tempYpos2;
    xspeed2 = tempXspeed2;
    yspeed2 = tempYspeed2;
  }
  void display() {
    stroke(0);
    fill(c2);
    rectMode(CENTER);
    rect(xpos2, ypos2, 50, 50);
  }
  void drive() {
    ypos2 = ypos2 - yspeed2;
    if (ypos2 > height) {
      ypos2 = 975;
    }
    if(ypos2 > 975) {
      ypos2 = 975;
    }
    if ((keyPressed) && (key == 'w')) {
      yspeed2 = 2;
    }
    if ((keyPressed) && (key == 's')) {
      yspeed2 = -2;
    }      
    if (yspeed2 > 0) {
      textAlign(CENTER);
      textSize(100);
      text("Going up", width/2, height/2); //xpos (half of 1920), ypos
    }
    if (yspeed2 < 0) {
      textAlign(CENTER);
      textSize(100);
      text("Going Down", width/2, height/2);
    }
  }
}
//sun
sun mysun;
sun mysun1;
class sun {
  color c3;
  float xpos3;
  float ypos3;
  int xspeed3;
  int yspeed3;

  //Constructor
  sun (color tempC3, float tempXpos3, float tempYpos3, int tempXspeed3, int tempYspeed3) {
    c3 = tempC3;
    xpos3 = tempXpos3;
    ypos3 = tempYpos3;
    xspeed3 = tempXspeed3;
    yspeed3 = tempYspeed3;
  }
  void display() {
    stroke(c3);
    fill(c3);
    ellipse(xpos3, ypos3, 150, 150);
  }
  void drive() {
    xpos3 = xpos3 + xspeed3;
    ypos3 = ypos3 - yspeed3;
    if (mysun1.xpos3 > 1920) {
      mysun1.xpos3 = 0;
    }
    if (mysun.xpos3 > 3920) {          //value dictates timing of moon/sun switch, must be adjusted with curves (perhaps timed)
      mysun.xpos3 = 0;
    }
    if (xpos3 > 1920) {
      ypos3 = 300;
    }
    if (xpos3 > width/2) {
      yspeed3 = -1;
    }
    if (xpos3 < width/2) {
      yspeed3 = 1;
    }
  }
}




void displayStartscreen() {   //Starting Screen
  background(#12D9FF);
}

void displayGame() {   
  background(#12D9FF);
  if (mysun.xpos3 >= width + 80) {         // D/N cycle
    background(#2C7AA2);
    mysun1.drive();
    mysun1.display();
  }
  myob4.drive();
  myob4.display();
  myrun.drive();
  myrun.display();
  mysun.drive();
  mysun.display();
  if (myrun.xpos2 + 110 > myob4.xpos1 - 170 && myrun.ypos2 > myob4.ypos1 - 60) {   //Collision between 0b4 and runner
    println("Hit");
    text("Hit!", 200, 100, 50);
    myob4.xpos1 = random(1920, 2400);
    score = score - 50;
  }
  if (myrun.xpos2 + 110 > myob4.xpos1 + 300 && myrun.ypos2 < myob4.ypos1 -60) {   //Scoring; Every 200 ms +1 is added to the score
    text("Dodge!", 200, 100, 50);
    if (millis() > time + 200) {
         score = score + 1;
         time = millis();
    }
  }
  //------------------------Backdrop
  fill(#5F5656);      
  noStroke();
  rect(0, 1200, 4000, 400);
  f = createFont("Times New Roman", 64, true);
  println(score * (-1));
  textSize(30);
  fill(0);
  text("Score:" + score, 1800, 100, 40);
  
}

void displayFail() {
  background(0);
  textAlign(CENTER);
  textSize(100);
  fill(#CE0202);
  text("You Died", width/2, height/2);
}
1 Like

You should use booleans instead of asking which int ‘state’ is. Instead of

int state;
int START_SCREEN = 0;
int GAME = 1;
int FAIL = 2;

you should have

boolean START_SCREEN = true; //because it's first
boolean GAME;
boolean FAIL;

and instead of asking

if ( state == 0) {
start = false;
if (keyPressed) {
state = 1;
}
} else if (state == 1) {
start = true;
} else if (state == 2) {
if (mouseButton == LEFT) {
state = 1;
}
}

you could do something like

if ( START_SCREEN) {
start = false;
GAME=false;
FAIL=false;
if (keyPressed) {
START_SCREEN=false;
GAME=true;
FAIL=false;
}
} else if GAME) {
start = true;
START_SCREEN=false;
FAIL=false;
} else if (FAIL) {
if (mouseButton == LEFT) {
GAME=true;
START_SCREEN=false;
FAIL=false;
}
}

and could work from there. Booleans are better for this type of thing because you don’t need to use switch(), and it’s easy to tell in the code when what is what.

Also, when pasting code, please use the correct format. To do this, press the button that looks like
</>

and past your code between the two '''s

I fully disagree with that.

To replace an int with 3 states with two boolean is not wise

is the correct way

Huh? I put three, as there is three states.
My code was

boolean START_SCREEN = true; //because it's first
boolean GAME;
boolean FAIL;

And doesn’t saying

state = START_SCREEN

Just make state 's values tranfer to START_SCREEN, not the other way round? I’ve read some posts that agree with ^

sorry, i would also opt for @Chrisir

int state=0;

version. ( the final int name = n; is also good but a beauty thing… )


reason:
if you have several boolean vars
( to select / show different screens )
you need to
add some code what treats them like a option group,
as only ONE may be true!
when using int this automatically means 'ONLY this n ’

also handling like

if ( keyCode == RIGHT ) state++;
if ( keyCode == LEFT )  state--;
state = constrain(state,0,8);

makes sense as operation concept for many screens


but as less screens you have as less important is that,
still i think the int state; will produce less errors.

1 Like

Right side value goes to left side

Sorry, I’m not sure what exactly to change in my void draw now, could you maybe clarify exactly what to change and why? Thanks :smiley:

Hi there Salttt,

In case you haven’t already, I really recommend starting fresh whenever you’re stuck. I don’t mean deleting your current game, but begin a new sketch and try to solve your issue in a simplified environment. It’s a great way to help you understand the topic you’re having trouble with, and at the same time you won’t mess up your original sketch. Once you understand you could try to implement it.

At this point you have trouble with the work flow of your program using switch. I made a simple example where this is fixed. Study it, play around with it, and once you understand try to implement it in your original sketch.

int screenNumber = 0;

void setup() {
  size(1920, 1080);
  textSize(96);
  textAlign(CENTER, CENTER);
}

void draw() {
  background(20);
  switch(screenNumber) {
  case 0: 
    text("beginning screen", width*.5, height*.5);
    break;
  case 1: 
    text("actual gameplay", width*.5, height*.5);
    break;
  case 2: 
    text("end screen", width*.5, height*.5);
    break;
  }
}

void mousePressed() {
  if (screenNumber == 2) {
    screenNumber = 0;
  } else {
    screenNumber++;
  }
}

ps. Advice for future posting: instead of posting a big sketch, it might be better to post a simplified version of the problem such as this one. :slight_smile:

2 Likes

Awesome, thank you! From now on I will definitely try out things in a more isolated state, it definitely help understanding the problem more. Cheers

1 Like

Regarding the first post: it seems redundant to test the state outside switch with of

Shouldn’t these lines be inside switch?

I think outside of the switch nothing should be in draw() except background

2nd

When we use function mousePressed or keyPressed we can use switch there also. So we have a means to control the input too.

(You have variable keyPressed inside the class; that’s okay but you could check the state there as well)