How to manage the steps of a game: increasing levels, displaying messages, etc.?

From Processing

Jump to: navigation, search

I will use the final code shown in How do I display a message for a few seconds?, and will build upon it.

I kept it procedural (no classes) to keep it simple and to avoid to afraid people having used classes yet.

// Illustration of http://wiki.processing.org/w/How_do_I_display_a_message_for_a_few_seconds%3F
 
// Ball handling
float posX, posY;
float speedX, speedY;
int radius;
color ballColor;
 
boolean bDisplayMessage; // False by default
int startTime; // The (last) time when the mouse have been clicked
final int DISPLAY_DURATION = 1000; // in milliseconds = 1s
 
void setup()
{
  size(600, 400);
  smooth();
 
  PFont f = createFont("Arial", 48);
  textFont(f);
 
  // Initialize the ball's data 
  posX = 120;
  posY = 50;
  speedX = -2;
  speedY = 3;
  radius = 24;
  ballColor = #002277;
}
 
void draw()
{
  // Erase the sketch area
  background(#AAFFEE);
  if (bDisplayMessage)
  {
    // Display the message instead of the ball
    fill(#FFAA88);
    text("You got it!", 150, height / 2);
    // If the spent time is above the defined duration
    if (millis() - startTime > DISPLAY_DURATION) 
    {
      // Stop displaying the message, thus resume the ball moving
      bDisplayMessage = false;
    }
  }
  else
  {
    // Compute the new ball position
    moveBall();
    // And display it
    displayBall();
  }
}
 
void mousePressed()
{
  // True if mouse position is close of the center of the ball (less than the radius in distance)
  // (Better than if (cond) b = true; else b = false; !)
  bDisplayMessage = dist(mouseX, mouseY, posX, posY) < radius;
  // Record the time of the event
  startTime = millis();
}
 
void moveBall()
{
  // Move by the amount determined by the speed
  posX += speedX;
  // Check the horizontal position against the bounds of the sketch
  if (posX < radius || posX > width - radius)
  {
    // We went out of the area, we invert the h. speed (moving in the opposite direction)
    // and put back the ball inside the area
    speedX = -speedX;
    posX += speedX;
  }
  // Idem for the vertical speed/position
  posY += speedY;
  if (posY < radius || posY > height - radius)
  {
    speedY = -speedY;
    posY += speedY;
  }
}
 
void displayBall()
{
  // Simple filled circle
  noStroke();
  fill(ballColor);
  ellipse(posX, posY, radius * 2, radius * 2);
}

Now, we will manage several states, to make it look like a professional game (well, almost!): we will display a welcome screen, waiting for the user to click on Play, then the level 1 of the game, and if successful, we go to level 2 (smaller ball, faster), and if hit, we display the game over screen, with the score.

The game is intently boring, to keep code small in this page...

Let's make the welcome screen:

void showWelcomeScreen()
{
  // Title
  textAlign(CENTER, CENTER);
  textSize(48);
  fill(#8888FF);
  text("Bouncing Ball", width / 2, height / 2);
 
  // Play button
  fill(#EEEE88);
  stroke(#AAAA55);
  rectMode(CENTER);
  rect(width / 2, 4 * height / 5, width / 5, height / 8, 10, 10);
  fill(#FF5500);
  textSize(32);
  text("PLAY", width / 2, 4 * height / 5);
 
  // Instructions
  textSize(24);
  fill(#5555AA);
  text("Click on the ball to win", width / 2, height / 2 + 50);
}

We have to react on a click on the button:

boolean isMouseOverPlayButton()
{
  // Half-wdith
  int hw = playButtonWidth / 2;
  // Half-height
  int hh = playButtonHeight / 2;
  // Returns true if mouse position is within the bounds of the button
  return mouseX >= playButtonX - hw && mouseX <= playButtonX + hw &&
      mouseY >= playButtonY - hh && mouseY <= playButtonY + hh;
}

I created constants, to avoid duplicating semi-arbitrary formulae, making them easier to change in one place. This would have been simpler if I made a Button class, but I prefer to stay away from them for this introductory article...

Note that I haven't defined the constants where I declared them, because at the time of initialization of these global variables, width and height are zero (setup(), thus size(), haven't been called yet).

int playButtonWidth, playButtonHeight;
int playButtonX, playButtonY;
 
void setup()
{
  // [...] cut out code
 
  playButtonWidth = width / 5;
  playButtonHeight = height / 8;
  playButtonX = width / 2;
  playButtonY = 4 * height / 5;
}
 
// In showWelcomeScreen()
  rect(playButtonX, playButtonY, playButtonWidth, playButtonHeight, 10, 10);

And we have to display the screen until the user clicks on the button:

// New global variable: remember, false by default
boolean bStarted;
 
void draw()
{
  // Erase the sketch area
  background(#AAFFEE);
 
  if (!bStarted)
  {
    showWelcomeScreen();
    return;
  }
 
  // Remainder of code as before
}
 
void mousePressed()
{
  // Check if we haven't started yet, and the click is within the button bounds
  if (!bStarted && isMouseOverPlayButton())
  {
    // Now, we can start!
    bStarted = true;
    return;
  }
 
  // Remainder of code as before
}

Now, we have to click the button to start the game.

[To Be Continued]

Personal tools