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

Files at this revision

API Documentation at this revision

Comitter:
Laphaze
Date:
Mon Jul 04 11:20:37 2016 +0000
Parent:
4:f0eb984c583d
Commit message:
Final commit

Changed in this revision

LM75B.lib Show annotated file Show diff for this revision Revisions of this file
MMA7660.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
diff -r f0eb984c583d -r f11bddc1baf0 LM75B.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LM75B.lib	Mon Jul 04 11:20:37 2016 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/neilt6/code/LM75B/#7ac462ba84ac
diff -r f0eb984c583d -r f11bddc1baf0 MMA7660.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MMA7660.lib	Mon Jul 04 11:20:37 2016 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/Sissors/code/MMA7660/#36a163511e34
diff -r f0eb984c583d -r f11bddc1baf0 main.cpp
--- 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