How to manage the steps of a game: increasing levels, displaying messages, etc.?
From Processing
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]