Topics Covered:

This lesson adds another 'phase' to the game- a waiting period that lets your player control when to start the game. This feature seems simpler than it is: you'll create a new function to achieve it.

/* * In this lesson, you will add a start screen that comes up * when the game is turned on and after a player gets a 'game over'. * * The start screen will be a little title card that goes up on the * LCD, and will wait for a button press to start playing. You will * implement this as a function, like drawing the crash, and drop * it in wherever it should pop up. */ #include "MakerScreenXVI.h" MakerScreenXVI lcd; byte run0[8] = { //legs in partial stride 0b00000, 0b01100, 0b01100, 0b01100, 0b01110, 0b01100, 0b01010, 0b01010 }; byte run1[8] = { //legs in full stride 0b00000, 0b01100, 0b01100, 0b01111, 0b01100, 0b01100, 0b01010, 0b10001 }; byte wall[8] = { //wall obstacle 0b11111, 0b10101, 0b11111, 0b10001, 0b11111, 0b10101, 0b11111, 0b10001 }; byte crash[8] = { //crashed JumpMan 0b00000, 0b00011, 0b01011, 0b00111, 0b00011, 0b00011, 0b00001, 0b00001 }; //The new icon for the jump part of the animation. byte jump[8] = { //mid-jump icon 0b00110, 0b10110, 0b01100, 0b01111, 0b01110, 0b01011, 0b10000, 0b00000 }; int position = 0; //holds the changing position of the cursor bool runState = 0; //which running animation to draw (0 or 1). int jumpState = 0; //0 ='pre-jump', 1 ='mid jump', 2='post jump' bool buttonState = 0; //will equal 1 after press, 0 after jump completed int wallPosition = 14; //wall can be placed from 0 to 15 int lives = 3; //starting number of lives int animationDuration = 300;//ms between animations of JumpMan's legs int runDuration = 600; //ms between moving JumpMan's position on the screen //Timers to update for each 'level' long animationTimer; long runTimer; void setup() { lcd.begin(); lcd.backlightOn(); lcd.createChar(0, run0); //partial stride character lcd.createChar(1, run1); //full stride character lcd.createChar(2, wall); //wall character in 'slot' 2 of custom characters lcd.createChar(3, crash); //splatted character against the wall lcd.createChar(4, jump); //mid-jump icon pinMode(6,INPUT_PULLUP); //button to trigger jump /* * The first time you want to put up the start screen is in setup, * after all the prepatory work, but before the game. You * want it to be before the timers get set, so the guy won't jump * ahead right away due to the delay. Jump to the bottom of the code * to see what the function looks like and what is in it. */ startScreen(); //Start both timers equal to millis() so that the difference between //millis and the variables is 0. animationTimer = millis(); runTimer = millis(); } void loop() { lcd.setCursor(0,0); lcd.write(4); //Show the jump icon alongside the lives counter lcd.print(lives); //Set the cursor depending on the state of the character if (jumpState == 0){ lcd.setCursor(position,1); } else if (jumpState == 1){ lcd.setCursor(position,0); } else if (jumpState == 2){ lcd.setCursor(position,1); } if (jumpState == 1){ //if jump has been activated.. lcd.write(4); //draw JumpMan mid-air } else{ lcd.write(runState); //draw the run0 or run1 animation } lcd.setCursor(wallPosition,1); lcd.write(2); //draw wall if ((digitalRead(6) == LOW)&&(jumpState == 0)){ buttonState = 1; //1 means a press is recorded } //Button is unpressed and a jump has been completed if ((digitalRead(6) == HIGH)&&(jumpState == 2)){ jumpState = 0; } if (millis() - animationTimer > animationDuration){ runState = 1 - runState; //draw the next JumpMan animation animationTimer = millis(); lcd.clear(); //clear the LCD to draw a new character } if (millis() - runTimer > runDuration){ //update position after runDuration position = position + 1; if (position == 16){ wallPosition = random(3,16); //place wall in column 3 through 15 position = 0; } //if button has been pressed and a jump hasn't been initiated... if ((buttonState == 1)&&(jumpState == 0)){ jumpState = 1; //signal a jump buttonState = 0; //reset button to 'unpressed' in the code } else if (jumpState == 1){ //true if jumpState set to one in the last loop jumpState = 2; //jump is marked as complete } if ((position == wallPosition)&&(jumpState != 1)){//if a jump is missed... drawCrash(); /* * Remove the speed reset. Reset the speed of the runner when the game * resets after all lives are lost. */ lives = lives - 1;//decrease lives by one with each crash /* * If the player has run out of lives, print a message to the screen * and reset the game. */ if (lives == 0){ //if out of lives... // Clear the LCD and write "Game Over" to it lcd.clear(); lcd.setCursor(4,0); lcd.print("Game Over"); delay(2000);//wait two seconds to restart the game //Reset all state variables: lives = 3; position = 0; buttonState = 0; runState = 0; //Reset speeds to 'level one' runDuration = 600; animationDuration = 300; /* * Show the start screen after the 'game over' is shown so that the * next game won't start until the button is pressed again */ startScreen(); } } else if (position == wallPosition){ runDuration = runDuration - 50;//increase speed that JumpMan moves on screen /* * If runDuration gets too small, JumpMan will just be a blur on the * screen. Keep its value at a minimum of 100. */ if (runDuration < 100){ runDuration = 100; } animationDuration = runDuration/2; //Move legs twice per position change } lcd.clear(); runTimer = millis(); } } void drawCrash(){ lcd.clear(); lcd.setCursor(position-1,1); //move cursor one position left of the collision lcd.write(3);//draw 'splatted' JumpMan lcd.setCursor(wallPosition,1); lcd.write(2); //draw the wall delay(1000); // Reset the variables to put the JumpMan back at the starting point position = 0; buttonState = 0; jumpState = 0; } /* * Defining the function for startScreen is just like drawCrash(). Unlike * the rest of the program, the order of the functions doesn't matter- * startScreen could come before drawCrash(). When the function is called, * the code jumps to it, runs it, and jumps back into place. */ void startScreen(){ lcd.clear(); //clear all of the old characters lcd.setCursor(2,0); //place cursor near the middle of Maker Screen lcd.print("Press button 6"); lcd.setCursor(4,1); //Move to the next line and complete message. lcd.print("to play!"); /* * A 'while' loop works a bit like an 'if' loop- it checks to see if * the condition in parenthesis is true, and if it is, does the * code in the following block. A while loop is different from * 'if'because 'if' runs it's code block code once per loop, but 'while' * checks its condition again after running. If the condition is still true, * it will run again, creating a loop of itself until the condition is no * longer true. */ while (digitalRead(6) == HIGH){//While the button isn't pressed... /* * Inside the 'while' loop, delay 10 milliseconds and check the 'while' * again. The program will just sit here as long as the button is not * pressed. */ delay(10); } /* * As the player presses the button, the code waits for them to let it go * so that the start screen doesn't jump to the game with the button held, * which would make JumpMan jump immediately. In this 'while', delay as * before. */ while (digitalRead(6) == LOW){//While the button is pressed... delay(10); } /* * Combining the 'while' loops creates a series of steps for the code to * complete before finishing the function. The button must be pressed and * then released to complete the startScreen(); function. */ /* * Once the button is pressed and released, this function is * complete and the code returns to the line of code just below the * function call (startScreen()). */ lcd.clear();//Clear the 'intro message'from the screen. } /* * You saw a 'while loop in this lesson. While loops are very useful * whenever you want to keep doing something until a condition is met. You * need to pay close attention to how they work, because a loop like: * * while(number<10){ * number = 9; * } * will continue forever once it begins. * */ //(c) 2017 Let's Start Coding. License: www.letsstartcoding.com/bsdlicense
 

Even the goal of 'wait for a button press to start the game' takes some thought and organization to achieve, especially if you want the game to be extremely reactive to the player pressing "Start".