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

Revision:
5:f11bddc1baf0
Parent:
4:f0eb984c583d
--- a/main.cpp	Fri Aug 01 14:32:40 2014 +0000
+++ b/main.cpp	Mon Jul 04 11:20:37 2016 +0000
@@ -1,19 +1,586 @@
+/*
+                     _                _        _____ _           _           
+                    / \   _ __  _ __ | | ___  |  ___(_)_ __   __| | ___ _ __ 
+                   / _ \ | '_ \| '_ \| |/ _ \ | |_  | | '_ \ / _` |/ _ \ '__|
+                  / ___ \| |_) | |_) | |  __/ |  _| | | | | | (_| |  __/ |   
+                 /_/   \_\ .__/| .__/|_|\___| |_|   |_|_| |_|\__,_|\___|_|   
+                     |_|   |_|                                           
+
+ +-+-+-+-+-+ +-+-+-+-+-+-+ +-+-+-+-+-+ +-+-+-+-+-+-+ +-+-+-+-+-+ +-+-+-+-+-+-+ +-+-+-+-+-+
+ |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);
 
-int main()
+// 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)
 {
-    while(1) {
-        lcd.cls();
-        lcd.locate(0,3);
-        lcd.printf("Pot 1 = %.2f", (float)pot1);
-        lcd.locate(0,14);
-        lcd.printf("Pot 2 = %.2f", (float)pot2);
-        wait(0.1);
+    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 !
\ No newline at end of file