Minigame based on Nucleo F103RB STM32F103RBT6 microcontroller with mBed Application shield

Dependencies:   C12832 LM75B MMA7660 mbed

Fork of apps-shield-pots by Chris Styles

- One player - Apple to collect - Monster to avoid - 3 life - 5 ammo - Dynamic difficulty

Playability : Move with accelerometer Shoot with joystick Notifications with RBG LED/Speaker

4 applicatives view - Menu - Ingame - Pause (press fire 2 seconds) - Game over

Have fun

main.cpp

Committer:
Laphaze
Date:
2016-07-04
Revision:
5:f11bddc1baf0
Parent:
4:f0eb984c583d

File content as of revision 5:f11bddc1baf0:

/*
                     _                _        _____ _           _           
                    / \   _ __  _ __ | | ___  |  ___(_)_ __   __| | ___ _ __ 
                   / _ \ | '_ \| '_ \| |/ _ \ | |_  | | '_ \ / _` |/ _ \ '__|
                  / ___ \| |_) | |_) | |  __/ |  _| | | | | | (_| |  __/ |   
                 /_/   \_\ .__/| .__/|_|\___| |_|   |_|_| |_|\__,_|\___|_|   
                     |_|   |_|                                           

 +-+-+-+-+-+ +-+-+-+-+-+-+ +-+-+-+-+-+ +-+-+-+-+-+-+ +-+-+-+-+-+ +-+-+-+-+-+-+ +-+-+-+-+-+
 |Will you be able to get the most apple as possible before the monster hunt you down ?|
 
 |Tips| -> Shoot the monster with right/left joystick
        -> Each 5 apple ate you level up and 2 ammo are added to your stock
        -> Each 10 apple ate you gain 1 life
        -> Pause the game by pressing Fire joystick 3 seconds
 
 |Warning| -> The monster is running faster each level
 +-+-+-+-+-+ +-+-+-+-+-+-+ +-+-+-+-+-+ +-+-+-+-+-+-+ +-+-+-+-+-+ +-+-+-+-+-+-+ +-+-+-+-+-+

*/

#include "mbed.h"
#include "LM75B.h"
#include "C12832.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string>
#include <vector>

class Apple
{
   public:
      float x; 
      float y; 
};

class Player
{
   public:
      float x;
      float y; 
      int life;  
      int eatenApple;
      int mobKilled;
      int ammo;
      bool firstSpawn;
      
      // Default class initialization
      Player() : life(3), ammo (3), firstSpawn( true )  {}
};

class Monster
{
   public:
      float x;
      float y; 
      bool killed;
      
    Monster() : killed( false ) {}
};

class Game
{
    public:
        bool started;  
        bool firstStart;
        bool paused;
        int level; 
        
        // Default class initialization
        Game() : started( true ), firstStart( true ), paused( false ), level (1) {}   
        
        void RestartGame (){
            started = true;
            level = 1;
        } 
};

// LCD initialization
C12832 lcd(D11, D13, D12, D7, D10);

// Potentiometer
AnalogIn pot1 (A0);
AnalogIn pot2 (A1);

// RBG LED
DigitalOut red_led(D5);
DigitalOut blue_led(D8);
DigitalOut green_led(D9);

// JOYSTICK
DigitalIn up(A2);
DigitalIn down(A3);
DigitalIn left(A4);
DigitalIn right(A5);
DigitalIn fire(D4);

// Temperature Sensor
LM75B sensor(D14,D15);

// Speaker
PwmOut spkr(D6);

// Class initialization
Apple apple;  
Player player;
Monster monster;
Game game;
std::vector<Apple> Apples;
std::vector<Monster> Monsters;

/** setLight
    Util method for switching LED color

    @param string color ColorName
*/
void setLight (string color)
{
     if(color == "blue")
     {
        red_led = 1;
        green_led = 1;
        blue_led = 0;
     }
     else if(color == "red")
     {
        red_led = 0;
        green_led = 1;
        blue_led = 1;
     }
     else if(color == "transparent")
     {
        red_led = 1;
        green_led = 1;
        blue_led = 1;
     }
     else {
        red_led = 1;
        green_led = 0;
        blue_led = 1;   
     }
}

void PlayMusic ()
{
    vector<int> sons;  
    spkr = 0.5;
    sons.push_back(800);
    sons.push_back(1100);                
    sons.push_back(400);
    sons.push_back(1200);                
    sons.push_back(900);
    int randomSound = rand() % 5;
    int valueSound = sons.at(randomSound);
    spkr.period(1.0/valueSound);
    wait(0.03);
    spkr = 0.0;
}
/** Shoot
    Shooting Lazer, takes right or left parameter

    @param string position
*/
void Shoot (string position)
{
    if(player.ammo != 0) // Check if player have enough ammo
    {
        if(position == "right") // Right shoot !
        {
            lcd.fillrect(player.x, player.y + 4, 127, player.y + 4, 1); // Display the laser !
            
            int verifShootMonster = Monsters[0].y - player.y; 
            
            if(verifShootMonster < 2 && player.x < Monsters[0].x) // Check if monster got hit
            {
                spkr.period(3.0/300); // Moskito crush sound ! :D
                spkr=0.9;
                wait(0.05);
                spkr.period(3.0/500);
                spkr=0.9;
                player.mobKilled++;
                Monsters[0].killed = true; // Monster is now hidden, to allow player to get the Apple safety
            }

            player.ammo--;
        } 
        if(position == "left") // Left shoot !
        {
            lcd.fillrect(player.x - 5, player.y + 4, 0, player.y + 4, 1); // Display the laser !
            
            int verifShootMonster = Monsters[0].y - player.y; 
            
            if(verifShootMonster < 2 && player.x > Monsters[0].x) // Check if monster got hit
            {
                spkr.period(3.0/300);
                spkr=0.9;
                wait(0.05);
                spkr.period(3.0/500);
                spkr=0.9;
                player.mobKilled++;
                Monsters[0].killed = true;     // Monster is now hidden, to allow player to get the Apple safety
            }
            player.ammo--;
        } 
    }
    else // Sorry, no ammo for the player :/
    {
        spkr.period(4.0/500);
        spkr=0.9;  
    }
}

/** ColisionEffect
    Action in case of collision with monster/apple

    @param string type
*/
void ColisionEffect(string type)
{
    if(type == "apple")
    {
        player.eatenApple++;
        setLight("green");
        
        /* Resetting monster/apple to generate randomly the next ground */ 
        Apples.clear();
        Monsters.clear();
        
        if(player.eatenApple % 10 == 0 && player.eatenApple > 9){ // Add 1 life each time player ate 10 apple
            player.life++;
        }
        if(player.eatenApple % 5 == 0) // LEVEL UP :D
        {
            game.level++;
            player.ammo += 2;
        } 
        
    }   
    else if (type == "monster")
    {
        wait(0.5);
        setLight("red");
        spkr.period(1.0/300);
        spkr = 0.9;
        player.life--;
        Monsters.clear();
        Apples.clear();
        
        if(player.life <= 0) // End of the game if player's life is equal to 0
        {
            game.started = false;
        }
    }
}

// The monster is following horizontally and vertically the player.
void MonsterTrackingPlayer()
{
    if(Monsters[0].y > 14) // Teleport the monster at the top of the map
    {
        Monsters[0].y = 0;     
    }
    else if(Monsters[0].y < 0) // Teleport the monster at the bottom of the map
    {
        Monsters[0].y = 13;   
    }
    else if(Monsters[0].y >= 0 && Monsters[0].y < 15) // Following player, from left to right
    {
        if(Monsters[0].y > player.y)
        {
            Monsters[0].y -= static_cast <float> (rand()) / static_cast <float> (RAND_MAX); // Trying new rand method which is approximatively..Random :)
        }
        else
        {
            Monsters[0].y += static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
        }
    }
    
    if(Monsters[0].x > 120) // Teleport player at the left of the map
    {
        Monsters[0].x = 0;     
    }
    else if(Monsters[0].x < 0)  // Teleport player at the right of the map // Unused in my case because monster's move are from left to right
    {
        Monsters[0].x = 120;   
    }
    else if(Monsters[0].x >= 0 && Monsters[0].x < 121) // "Randomize" a bit the monster's move
    {
        Monsters[0].x += static_cast <float> (rand()) / static_cast <float> (RAND_MAX / game.level);  // Monster's move is faster each level
    }
    
    // Display the monster
    lcd.locate(Monsters[0].x, Monsters[0].y);
    lcd.printf("x");    
}

// Display the start screen Menu
void PrintStartMenu()
{
    setLight("blue");
    lcd.fillrect(127, 0, 0, 0, 1);
    lcd.locate(35, 2);
    lcd.printf("Apple finder :D");
    
    lcd.fillrect(127, 12, 0, 12, 1);
    
    lcd.locate(0, 13);
    lcd.printf("Monster: X");
    
    lcd.locate(55, 13);
    lcd.printf("Apple: O");
    
    lcd.locate(96, 13);
    lcd.printf("You: +");
            
    lcd.locate(0, 22);
    lcd.printf("Presse fire to launch game !");
}

// Display the bottom stats ingame menu
void PrintBottomMenu()
{
    lcd.locate(0, 23);
    lcd.fillrect(0, 30, 0, 30, 1);
    lcd.printf("Apple: %d", player.eatenApple);
    // Vertical divider
    lcd.fillrect(42, 23, 42, 32, 1);
                
    lcd.locate(45, 23);
    lcd.printf("LVL %d", game.level);
    
    // Vertical divider
    lcd.fillrect(73, 23, 73, 32, 1);
    
    lcd.locate(79, 23);
    lcd.printf("~%d", player.ammo);
    
    // Vertical divider
    lcd.fillrect(92, 23, 92, 32, 1);
    
    lcd.locate(95, 23);
    lcd.printf("Life: %d", player.life);
}

// Display the Game Over screen Menu
void PrintGameOverMenu()
{
    lcd.fillrect(127, 0, 0, 0, 1);
    lcd.locate(15, 2);
    lcd.printf("Game OVER :/ LVL %d", game.level);
    lcd.fillrect(127, 12, 0, 12, 1);
    
    lcd.locate(0, 13);
    lcd.printf("Apple ate: %d", player.eatenApple);
    
    lcd.locate(70, 13);
    lcd.printf("Mob killed: %d", player.mobKilled);
            
    lcd.locate(10, 22);
    lcd.printf("Presse fire to restart");    
}


// Default thread
int main()
{   

    float verifXApple, verifYApple, verifXMonster, verifYMonster = 0.0;
    int scrollPosition = 0;
    int breakTimer = 0;
    bool blinkEnd = true;
    bool blinkScreenPause = true;
    
    // Sound off
    spkr = 0.0;
    
    /* I'm using the temp sensor to generate random number that i'll pass as parameter for the srand fonction with time clock, it allows a different generation (and not random) number each appStart time */
    int randHack = int(sensor.temp() + 0.5);
    srand(randHack);
    
    while(true) // Main thread
    {
        /* ------ */
        
        PrintStartMenu();
        
        /* ------ */ 
            
        while(game.firstStart) // First Menu -- Explications
        {
            if(fire) // If user press fire, start the game !
            {
                game.firstStart = false;
            }
        }
        
        // Play while player's alive
        while(game.started == true) {
            
            spkr = 0.0;
            lcd.cls(); // Initial screen clear
            
            while(game.paused == true)
            {
                PrintBottomMenu(); // Display the stats bottom menu
                
                blinkScreenPause = !blinkScreenPause; // Blink and invert the screen color, fun effect
                
                if(blinkScreenPause) // Black foreground
                {
                    lcd.fillrect(127, 0, 0, 22, 1);
                }
                else // White foreground
                {
                    lcd.fillrect(127, 0, 0, 22, 0);
                }
                
                if(scrollPosition < 12) // Scrolling text vertically, and teleport it at the top if he reach the bottom limit
                {
                    lcd.locate(32, scrollPosition);
                    lcd.printf("Game PAUSED");
                }
                else
                {
                    scrollPosition = 1;
                    lcd.locate(32, scrollPosition);
                    lcd.printf("Game PAUSED");          
                }
                
                scrollPosition += 2;
                
                if(fire) // Resume pause
                {
                    if(breakTimer >= 2)
                    {
                        game.paused = false;   
                        breakTimer = 0; 
                    }
                    else
                    {
                        breakTimer++;
                    } 
                }
                            
                wait(0.5);
            }
            
            if(player.firstSpawn == true) // Assign the player to default location, but seems little bit buggy due to the the potentiometer's value which is not reset to zero every time the system reboot.
            {
                setLight("green");
                player.x = 0;
                player.y = 0;    
            }            
            else // Player positionning with potentiometer
            {
                player.x = (float)pot2 * 122;
                player.y = (float)pot1 * 15;
            }
            
            player.firstSpawn = false;
            
            // Random apple generation 
            if(Apples.size() == 0)
            {
                apple.x = rand() % 122;
                apple.y = rand() % 15;
                Apples.push_back(apple); 
            }
            
            // Random monster generation 
            if(Monsters.size() == 0)
            {
                monster.x = rand() % 122;
                monster.y = rand() % 15;
                
                Monsters.push_back(monster);    
            }
            
            // Bottom map border
            lcd.fillrect(0, 22, 128, 22, 1);
            
            // Colision Verification with apple
            verifXApple = Apples[0].x - player.x;
            verifYApple = Apples[0].y - player.y + 4.0;
            
            // Check collision with apple
            if(verifXApple < 4 && verifXApple > -4 && verifYApple < 5 && verifYApple > -5)
            {
                ColisionEffect("apple");
            }
            
            // Verification colision with monster
            verifXMonster = Monsters[0].x - player.x;
            verifYMonster = Monsters[0].y - player.y + 4.0;
            
            // Check collision with monster
            if(verifXMonster < 4 && verifXMonster > -4 && verifYMonster < 5 && verifYMonster > -5 && Monsters[0].killed == false)
            {
                ColisionEffect("monster");
            }
            else
            {
                PlayMusic();  
            }      
                        
        
            /* ------ */
            
            PrintBottomMenu();
            
            /* ------ */ 
                        
            if(right) // Joystick event right/left
            {
                Shoot("right");
            }
            if(left)
            {
                Shoot("left");
            }
            
            if(fire)
            {
                if(breakTimer >= 2)
                {
                    game.paused = true;   
                    breakTimer = 0; 
                }
                else
                {
                    breakTimer++;
                } 
            }
            
            // Player positionning
            lcd.locate(player.x, player.y);
            lcd.printf("+");  
            
            // Apple positionning
            lcd.locate(Apples[0].x, Apples[0].y);
            lcd.printf("o");
            
            if(Monsters[0].killed == false)
            {
                MonsterTrackingPlayer();
            }
            
            wait(0.15);
        }
        
        lcd.cls(); // Clear screen before GameOverMenu
        
        while(game.started == false) // GameOver Menu
        {
            /* ------ */
            
            PrintGameOverMenu();
            
            /* ------ */
            
            spkr = 0.0;
            if(blinkEnd == true) // Making cool effect with light
            {
                blinkEnd = !blinkEnd;
                setLight("red");
            }
            else
            {
                blinkEnd = !blinkEnd;
                setLight("transparent");
            }
            
            if(fire) // Start a new game
            {
                player.life = 3;
                player.eatenApple = 0;
                player.ammo = 1;
                player.mobKilled = 0;
                game.RestartGame();
            }
        }
    }
}

// Wooh, you finished it !