Simple Zombie game with Arduino LCD and button

Here's a small project I did just to get some practice using an LCD I recently bought.

It's a extremely simple Zombie survival game. Check out the code, some pictures and a small video here.

Not what I expected from the title, but it seems fun :smiley: A bit like those flashgames, so simple, but still fun to do :wink:

Nice one :slight_smile:

What did you expect then? (Just a bit curious about the first thing that popped into your head when your read the title).

Also it was very hard to refrain from writing "Dead simple Zombe game ..."
;D

What I expected might actually be possible as an extension.
"Real" zombies on the display (custom characters ?) in some form on the right side, and you shooting from the left side (fire-ing dashes for example)

Damn.. sounds like fun to make actually :smiley:

Yeah, like a two row shoot-em-up.

On the thought of evolving the game I hope to get the scare/action part up even higher once I get the rumbler installed on my version.

Looks fun :sunglasses:

How about something like this :smiley:

Gun might want to be a bit higher though :wink:

Exactly what Beige just drew! :smiley:
Would be mainly graphics, the gameplay could still be the same as you have now.

Zombie appears: draw zombie
Zombie dies: don't draw zombie

Press button and zombie is alive: display bullet and move it to the right fast

Walking speed of the zombie could be related to the time you have left

Yeah, that sounds like it would work.
Maybe I'll look into it in the morning, now it's time for a different kind of z's.

Or you do it :wink:

What about a 2 button game, screen vertical, at the bottom is a sorta back view, a little bit up, sorta 45 degree angle view of the player. (sorry, i didn't know how to explain it well)
The zombies come down from the top, and you hit them when they hit the bottom. (story: you are only accurate firing at point blank range, so you must hit when they get close, but dont miss!)
Sorta like guitar hero! Zombie hero!
Maybe even make a catchy tune, and have it synced to it!

Zombie guitar hero. I like it!
:smiley:

Or you do it :wink:

I wish.. waiting on my arduino + box-of-parts to arrive :stuck_out_tongue:

Very cool!

Took the liberty to add some zombie graphics :smiley:
Removed some of the comment as it would not fit on the forum otherwise, sorry bout that.

/* 
  Zombie Showdown
  By Markus Ulfberg 2010-01-12
  
  More Arduino stuff and future updates of Zombie Showdown at:
  http://genericnerd.blogspot.com
*/

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

char* gameText[]={"Zombie Showdown",// 0 Title 
                  "Kill to Start",  // 1 
                  "Let's go!",      // 2
                  "Zombie!!!",      // 3                  
                  "You killed it.", // 4
                  "You are dead.",  // 5
                  "Game Over",      // 6
                  "Score: "         // 7
                  };         

// Custom characters for the zombie graphics
byte zombie_head[8] = {
  B00000,
  B00110,
  B01111,
  B11101,
  B11111,
  B11100,
  B11011,
  B11110,
};

byte zombie_body[8] = {
  B11100,
  B11111,
  B11111,
  B11100,
  B11100,
  B11100,
  B11100,
  B11100,
};
byte zombie_arm[8] = {
  B00000,
  B11110,
  B11111,
  B00001,
  B00000,
  B00000,
  B00000,
  B00000,
};

byte zombie_head_expl[8] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B01000,
  B11011,
  B11110,
};

// Button variables
const int buttonPin = 2;

// Two values for debounceing
int buttonState;
int lastButtonState = LOW;

long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

// Stores value of button 1 = pressed 0 = released 
int buttonPress = 0;

// Title screen blink variables
long lastBlinkTime = 0;
long blinkDelay = 500;
int blinkState = 0;

// Zombie health a random number between 1 and 5
int zombie;

// Time since last zombie apperance
long lastZombieTime = 0;

long zombieDelay;

long zombieBite;

// Status of zombie apperance 1 = zombie 0 = no zombie
int zombieState = 0;

// Total steps the zombie can take
int zombieSteps = 15;
int zombiePosition = 0;
int zombieLastPosition = 0;
int zombieSpeed = 0;

// Status of player 1 = alive 0 = dead
int playerAlive = 1;

// gameRun sets start screen or runs the game
int gameRun = 0;

// Score
int score = 0;

void setup() {
  
  // set up the LCD's number of rows and columns: 
  lcd.begin(16, 2);
  
  // DEBUG ONLY
  Serial.begin(9600);
    
  // Set up the button
  pinMode(buttonPin, INPUT);
  buttonState = digitalRead(buttonPin); 
  
  // Use unconnected analog input pin
  // to generate a random seed for the random generator
  randomSeed(analogRead(0));
  
  // Generate zombie characters
  lcd.createChar(0, zombie_head);
  lcd.createChar(1, zombie_body);
  lcd.createChar(2, zombie_arm);
  lcd.createChar(3, zombie_head_expl);

  // The timeframe where a new Zombie appears 
  // this first Zombie will have a shorter random time frame 
  zombieDelay = random(200,10000);
  
  // The timeframe for the first zombie bite
  zombieBite = random(2000,7000);
  setZombieSpeed();
  
}

void loop() {
  
  // Start sequence
  gameStart();
   
  // Gameplay
  gameExecute();
  
  // GameOver
  gameOver();
  
} // loop end

void gameStart() {
  
  while (gameRun == 0) {
    // Set the cursor
    lcd.setCursor(0,0);
    
    // print the name of the game
    lcd.print(gameText[0]);
  
  
    // Pause for blink
    if ((millis() - lastBlinkTime) > blinkDelay) {
    
      // If blinkState is OFF turn it ON
      if (blinkState == 0) {
      
        // Clear the LCD and set the cursor
        lcd.clear();
    
        // move the cursor down 
        lcd.setCursor(0,1);
        // print the blinking text
        lcd.print(gameText[1]);
    
        // Set the cursor for non blinking text
        lcd.setCursor(0,0);
    
        // since blink cleared the whole LCD
        // we need print the name of the game again
        lcd.print(gameText[0]);
      
        // set blinkState to ON
        blinkState = 1;
      // If blinkState is OFF turn it ON
      } else {
      
        // Clear the LCD and set the cursor
        lcd.clear();
    

        // Set the cursor for non blinking text
        lcd.setCursor(0,0);
    
        // print the name of the game
        lcd.print(gameText[0]);
      
        // Set blink to OFF
        blinkState = 0;
      
      } // END: else 
    
      // store the new blink time
      lastBlinkTime = millis();
    

    } // END: if ((millis() - lastBlinkTime) > blinkDelay)
    
    // Check if button is pressed 
    if (button() == 1) {
      // If so start the game
      gameRun = 1;
      playerAlive = 1;
      
      // reset score
      score = 0;
    } // END: if (button() == 1)
    
  } // END: while game start    
} // END: void gameStart 

void gameExecute() {
  // check wether button is pushed to run game
  while (gameRun == 1) {
      lcd.clear();
      lcd.print(gameText[2]);
      // small delay to get ready
      delay(2000);
 
      // Check if a zombie is here
      if (zombieState == 1) {
        // tell the player that a zombie is here
        lcd.clear();         
        // lcd.print(gameText[3]);
        // Put the zombie in position 0;
        drawZombie();
       
        // Set the strenght and speed of of the zombie
        zombie = random(1,5);
             
         // Resets the zombie timer 
         // this one is for the speed of which the zombie attacks 
         lastZombieTime = millis(); 
       
        // The action part
        while (zombie > 0) {
         // Find out where the zombie has to stand
         zombiePosition = ((millis() - lastZombieTime) / zombieSpeed);
         
         if (zombiePosition != zombieLastPosition) {
            // If it moved, redraw
            zombieLastPosition = zombiePosition;
            drawZombie();
         }
         
         // Check if button is pressed 
         if (button() == 1) {
           // If so remove 1 health from zombie
           zombie--;
         }
        
         // check if the zombie bites
         if ((millis() - lastZombieTime) > zombieBite) {
            
           // player is bitten and killed
           // Print information on death
           lcd.clear();
           lcd.print(gameText[5]);      
           delay(2000);
            
           // Make sure all loops are exited
           gameRun = 0;
           zombie = 0;
         }
          
       } // END: while zombie > 0
     
       // Add score, first check if the zombie was killed or 
       // it was the player who died and zombie was just reset
       if (gameRun == 1) {
         // The zombie was killed 
         zombieState = 0;
         // Add to the players score
         score++;
         //lcd.clear();
         // Print information of kill
         //lcd.print(gameText[4]);
         lcd.setCursor(zombiePosition,0);
         lcd.write(3);

         // Pause for a while
         delay(1000);
       } 
        
     } else { // END: if Zombie State and Start else 
      
       // zombieState is 0 check if enough time 
       // has passed since last zombie
       if ((millis() - lastZombieTime) > zombieDelay) {
         // A new zombie is here
         zombieState = 1;
         // reset random zombieDelay
         zombieDelay = random(200,2000);
        
         // reset random zombieBite time;
         zombieBite = random(2000,7000);
         setZombieSpeed();
         
         // reset position
         zombiePosition = 0;
         zombieLastPosition = 0;
         
       } // END: if ((millis() - lastZombieTime) > zombieDelay)
     
     } // END: else 

  }  // END: while game run 
  
} // END: gameExecute 

// Calculate the zombie speed, how many ms per step?
void setZombieSpeed() {
  zombieSpeed = zombieBite / zombieSteps;
}

// Draw the zombie on the screen in the correct position
void drawZombie() {
 lcd.clear();
 lcd.setCursor(zombiePosition,0);
 lcd.write(0);
 lcd.setCursor(zombiePosition,1);
 lcd.write(1);
 lcd.setCursor(zombiePosition+1,1);
 lcd.write(2); 
}

int button() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  } 
  
  if ((millis() - lastDebounceTime) > debounceDelay) {
    buttonState = reading;    
            
    // If button is pressed down 
    if (buttonState == HIGH) {
      // store the state of the button
      buttonPress = 1;             
    }
    // If button is up ...
    if (buttonState == LOW) {
      // ... and was just down i.e released
      if (buttonPress == 1) {
        // Store the new state of the button
        buttonPress = 0;
        
        // also save the reading since we terminate in the next step        
        lastButtonState = reading;      
        
        // Terminate the button() function and return 
        // a positive button press
        return 1;
      }
    } // END: If buttonState == LOW
  } // END: If millis... 
  
  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = reading;
  
} // END: void button()
  
void gameOver() {
  lcd.clear();
  lcd.setCursor(0,0);
  // Print Game Over
  lcd.print(gameText[6]);
  lcd.setCursor(0,1);
  // Print Score
  lcd.print(gameText[7]);
  lcd.print(score);
  // Pause for a while 
  delay(4000); 
  
}

Nice work!

It turned out to be quite fun aswell. I'd love to post this on my blog, so if you add your name to the top (how does "Graphics engine by Blammers sound to you? ;D ) and send me the full source code with comments (the one that didn't fit here). I'll put it up there. Or you could post it yourself as a comment on the original post.

Again, really nice work, I thought it would require alot more code when I first started thinking about it.

Took me a while but here's the blogpost with pictures and video from Zombie Showdown with graphics.