This lesson is about visual improvement to your game. You can spend as much time on these types of features as you'd like and, as long as you understand how to fit them into the existing program, you can create all kinds of new characters and conditions to show them.
Topics Covered:
/*
* In this lesson, you'll add a new custom character that is triggered when
* JumpMan is mid-jump to give him the appearance of leaping over the wall.
*/
#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 points = 0; //jumps without hitting a wall
long animationTimer; //tracks animation (custom character) updates
long runTimer; //tracks position updates
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
//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); //upper left of the screen
lcd.print("Pt: ");
lcd.print(points);
//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);
}
/*
* Draw the new mid-jump animation, which has been controlled
* only by runState until now. Make the drawing conditional
* based on jumpState, 'if' jumpState is 1, then draw the 'jump' icon.
* Else, draw the running animation as you have before.
*/
if (jumpState == 1){ //if jump has been activated...
lcd.write(4); //draw JumpMan mid-air
}
/*
* An 'else' statement goes after 'if' and all the 'else if' statements
* that follow it. It tells the program "if all preceeding 'if' conditions
* are not true, then do what comes in the block after".
*/
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 > 300){//Update animation every 300 ms
runState = 1 - runState; //draw the next JumpMan animation
animationTimer = millis();
lcd.clear(); //clear the LCD to draw a new character
}
if (millis() - runTimer > 600){//Every 600 milliseconds, run this...
position = position + 1; //move character one space to the right
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)){//check for a crash
points = 0; //remove all points if you crash
drawCrash();
}
//If you've reached the wallPosition and haven't crashed, you must have
//survived the leap. Add a point
else if (position == wallPosition){
points = points + 1;
}
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;
}
/*
* A new character adds more realism to your game. Because your game has
* 'state variables' that change as the program changes, you are able to
* identify spots in the game where something should happen and then quickly
* find those in the code and make the update.
*/
//(c) 2017 Let's Start Coding. License: www.letsstartcoding.com/bsdlicense
Heads up! You need our Chrome App to run this code.
Success!
Compile errors:
Serial port monitor:
Input:
In this program you created a 'special case' for the custom character when JumpMan is in the air over a wall. This special case has a few conditions: the button must be pressed and the character must be above the wall. Your 'else' statement covers every other drawing in the game. 'Else' statements are designed to blanket 'all other cases'.