This is a ball on the Mbed.

Dependencies:   4DGL-uLCD-SE IMUfilter ITG3200 Music mbed-rtos mbed

Revision:
0:680348a938f8
diff -r 000000000000 -r 680348a938f8 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Mar 14 17:03:16 2014 +0000
@@ -0,0 +1,384 @@
+        #include <math.h>
+    #include <time.h>
+     
+    #include "mbed.h"
+    #include "uLCD_4DGL.h"
+    #include "rtos.h"
+    #include "IMU_RPY.h"
+     
+    // game configuration macros
+    #define NUMBER_OF_ROUNDS 3
+    #define CURSOR_SPEED 0.5
+    #define CURSOR_COLOR 0xFFFF00
+    #define SPACE_COLOR BLACK
+    #define WALL_COLOR RED
+    #define START_COLOR GREEN
+    #define END_COLOR BLUE
+     
+    // game mechanism macros
+    #define MAZE_DIMENSION 25
+    #define SCALAR (125 / MAZE_DIMENSION)
+    #define START_BLOCK 3
+    #define END_BLOCK 2
+    #define WALL_BLOCK 1
+    #define SPACE_BLOCK 0
+     
+    // prototypes in alphabetical order
+    bool checkVictory();
+    void displaySplashScreen();
+    void displayMaze();
+    void displayVictory();
+    void displayEndGame();
+    void generateMaze();
+    void depthFirstSearch(int r, int c);
+    void updateVelocity();
+    void updateBall();
+    void xthread(void const *args);
+    void ythread(void const *args);
+     
+    // display variables
+    uLCD_4DGL uLCD(p9, p10, p11);
+     
+    // cursor variables
+    Mutex x_mutex, y_mutex;
+    char cursor_x_pos, cursor_y_pos;
+    char old_cursor_x_pos, old_cursor_y_pos;
+    float ballxvel, ballyvel;
+     
+    // start and end variables
+    char start_x, start_y;
+    char end_x, end_y;
+     
+    // maze data structure
+    char maze[MAZE_DIMENSION][MAZE_DIMENSION];
+     
+    // level counter
+    char level = 0;
+     
+    int main()
+    {
+        pc.printf("Super Mbed Ball!!!!!\n\r");
+     
+        // set up gyroscope/accelerometer (rpy = roll, pitch, yaw)
+        rpy_init();
+     
+        //Overclock uLCD
+        uLCD.baudrate(3000000);
+     
+        //Title Screen
+        displaySplashScreen();
+     
+        //Start physics engine threads
+        Thread t1(xthread);
+        Thread t2(ythread);
+     
+        // each iteration runs a complete game until user wins.
+        // wait for user to complete max allowed levels before
+        // terminating
+        while(level < NUMBER_OF_ROUNDS) {
+     
+            //Initial velocity
+            ballxvel = 0;
+            ballyvel = 0;
+     
+            //create Maze
+            generateMaze();
+            displayMaze();
+     
+            //Game Execution Loop
+            while (checkVictory() == false) {
+                updateVelocity();
+                updateBall();
+            }
+     
+            // victory splash screen
+            displayVictory();
+           
+            // increment level counter
+            level++;
+        }
+       
+        // display last end game screen before exiting program
+        displayEndGame();
+    }
+     
+    // checks if cursor has  moved to the end block
+    bool checkVictory()
+    {
+        // check if cursor made it to end row and column
+        return(maze[cursor_x_pos][cursor_y_pos] == END_BLOCK);
+    }
+     
+    // depth first search, called by generateMaze()
+    void depthFirstSearch(int r, int c)
+    {
+        // 4 random direction
+        int randDirs1[] = {1, 2, 3, 4};
+        int randDirs2[] = {4, 2, 3, 1};
+        int *randDirs = NULL;
+     
+        if (rand() % 2)
+            randDirs = randDirs1;
+        else
+            randDirs = randDirs2;
+     
+        // Examine each direction
+        for (int i = 0; i < 4; i++) {
+            switch (randDirs[i]) {
+                case 1: // Up
+                    // Whether 2 cells up is out or not
+                    if (r - 2 <= 0)
+                        continue;
+                    if (maze[r - 2][c] != 0) {
+                        maze[r - 2][c] = SPACE_BLOCK;
+                        maze[r - 1][c] = SPACE_BLOCK;
+                        depthFirstSearch(r - 2, c);
+                    }
+                    break;
+                case 2: // Right
+                    // Whether 2 cells to the right is out or not
+                    if (c + 2 >= MAZE_DIMENSION - 1)
+                        continue;
+                    if (maze[r][c + 2] != 0) {
+                        maze[r][c + 2] = SPACE_BLOCK;
+                        maze[r][c + 1] = SPACE_BLOCK;
+                        depthFirstSearch(r, c + 2);
+                    }
+                    break;
+                case 3: // Down
+                    // Whether 2 cells down is out or not
+                    if (r + 2 >= MAZE_DIMENSION - 1)
+                        continue;
+                    if (maze[r + 2][c] != 0) {
+                        maze[r + 2][c] = SPACE_BLOCK;
+                        maze[r + 1][c] = SPACE_BLOCK;
+                        depthFirstSearch(r + 2, c);
+                    }
+                    break;
+                case 4: // Left
+                    // Whether 2 cells to the left is out or not
+                    if (c - 2 <= 0)
+                        continue;
+                    if (maze[r][c - 2] != 0) {
+                        maze[r][c - 2] = SPACE_BLOCK;
+                        maze[r][c - 1] = SPACE_BLOCK;
+                        depthFirstSearch(r, c - 2);
+                    }
+                    break;
+            }
+        }
+    }
+     
+    //Take whats in the mazearr and write it
+    void displayMaze()
+    {
+     
+        // Clear previous maze
+        uLCD.filled_rectangle(0, 0, 127, 127, SPACE_COLOR);
+     
+        // display start location
+        uLCD.filled_rectangle(start_x * SCALAR, start_y * SCALAR,
+                              (start_x + 1) * SCALAR - 1, (start_y + 1) * SCALAR - 1, START_COLOR);
+     
+        // display end location
+        uLCD.filled_rectangle(end_x * SCALAR, end_y * SCALAR,
+                              (end_x + 1) * SCALAR - 1, (end_y + 1) * SCALAR - 1, END_COLOR);
+     
+        // display walls of maze
+        for (int i = 0; i < MAZE_DIMENSION; i++) {
+            for (int j = 0; j < MAZE_DIMENSION; j++) {
+                if (maze[i][j] == WALL_BLOCK)
+                    uLCD.filled_rectangle(i * SCALAR, j * SCALAR, (i + 1) * SCALAR - 1, (j + 1) * SCALAR - 1, WALL_COLOR);
+            }
+        }
+    }
+     
+    //Game title screen
+    void displaySplashScreen()
+    {
+        uLCD.text_width(2);
+        uLCD.text_height(2);
+        uLCD.locate(0, 0);
+        uLCD.printf("SuperMbed");
+        uLCD.text_width(2);
+        uLCD.text_height(3);
+        uLCD.locate(2, 1);
+        uLCD.printf("Ball!");
+        wait(3);
+    }
+     
+    //Victory screen - 5 sec delay and then next level
+    void displayVictory()
+    {
+        uLCD.text_width(2);
+        uLCD.text_height(2);
+        uLCD.locate(1, 3);
+        uLCD.printf("VICTORY!");
+        wait(5);
+    }
+     
+    // End game screen
+    void displayEndGame() {
+        // wipe screen
+        uLCD.filled_rectangle(0, 0, 127, 127, BLACK);
+       
+        // write game over
+        uLCD.text_width(2);
+        uLCD.text_height(2);
+        uLCD.locate(1, 3);
+        uLCD.printf("GAME OVER");
+    }
+     
+    // randomely generates a maze using depth first search
+    void generateMaze()
+    {
+        // Initialize all spaces to walls
+        for (int i = 0; i < MAZE_DIMENSION; i++)
+            for (int j = 0; j < MAZE_DIMENSION; j++)
+                maze[i][j] = WALL_BLOCK;
+     
+        // unused z-value of gyroscope will be random seed
+        srand(imuFilter.getYaw());
+     
+        // calculate starting row and column of maze DFS
+        // starting row and column must be an odd number
+        int seed = 0;
+        while(seed % 2 == 0)
+            seed = rand() % (MAZE_DIMENSION -1) + 1;
+     
+        pc.printf("seed: %d\r\n", seed);
+     
+        // Starting cell
+        maze[seed][seed] = SPACE_BLOCK;
+     
+        // Allocate the maze with recursive method
+        depthFirstSearch(seed, seed);
+     
+        // find start and end positions
+        start_x = start_y = 0xF;
+        end_x = end_y = 0;
+        for (int i = 0; i < MAZE_DIMENSION; i++) {
+            for (int j = 0; j < MAZE_DIMENSION; j++) {
+     
+                if (maze[i][j] == SPACE_BLOCK) {
+                    // start space
+                    if((i*MAZE_DIMENSION + j) < (start_x*MAZE_DIMENSION + start_y)) {
+                        start_x = i;
+                        start_y = j;
+                    }
+     
+                    // end space
+                    if((i*MAZE_DIMENSION + j) > (end_x*MAZE_DIMENSION + end_y)) {
+                        end_x = i;
+                        end_y = j;
+                    }
+                }
+            }
+        }
+     
+        // reset cursor starting position
+        cursor_x_pos = old_cursor_x_pos = start_x;
+        cursor_y_pos = old_cursor_y_pos = start_y;
+     
+        // mark spots in maze data structure
+        maze[start_x][start_y] = START_BLOCK;
+        maze[end_x][end_y] = END_BLOCK;
+     
+    }
+     
+    //Move the ball around and draw to the screen
+    void updateBall()
+    {
+        x_mutex.lock();
+        y_mutex.lock();
+     
+        // redraw ball only if the position has changed
+        if (cursor_x_pos != old_cursor_x_pos || cursor_y_pos != old_cursor_y_pos) {
+     
+            //Wipe the old ball
+     
+            uLCD.filled_rectangle(old_cursor_x_pos * SCALAR, old_cursor_y_pos * SCALAR,
+                                  (old_cursor_x_pos + 1) * SCALAR - 1, (old_cursor_y_pos + 1) * SCALAR - 1, SPACE_COLOR);
+     
+            //Out with the old in with the new!
+            uLCD.filled_rectangle(cursor_x_pos * SCALAR, cursor_y_pos * SCALAR,
+                                  (cursor_x_pos + 1) * SCALAR - 1, (cursor_y_pos + 1) * SCALAR - 1, CURSOR_COLOR);
+     
+            // store new position
+            old_cursor_x_pos = cursor_x_pos;
+            old_cursor_y_pos = cursor_y_pos;
+        }
+     
+        x_mutex.unlock();
+        y_mutex.unlock();
+    }
+     
+     
+    //This will be where the gyro values are used to accelerate/decelerate the ball
+    void updateVelocity()
+    {
+        x_mutex.lock();
+        y_mutex.lock();
+     
+        // sample gyroscope/accelerometer through filter
+        ballxvel = toDegrees(imuFilter.getPitch()) / -10;
+        ballyvel = toDegrees(imuFilter.getRoll()) / 10;
+     
+        // bound velocities to max speed for x
+        if (ballxvel > 1)
+            ballxvel = CURSOR_SPEED;
+        else if (ballxvel < -1)
+            ballxvel = -CURSOR_SPEED;
+     
+        // bound velocities to max speed for y
+        if (ballyvel > 1)
+            ballyvel = CURSOR_SPEED;
+        else if (ballyvel < -1)
+            ballyvel = -CURSOR_SPEED;
+     
+        // round to 2 decimal places
+        ballxvel = floorf(ballxvel * 100.0) / 100.0;
+        ballyvel = floorf(ballyvel * 100.0) / 100.0;
+     
+        x_mutex.unlock();
+        y_mutex.unlock();
+    }
+     
+     
+    //xthread and ythread act as the physics engine, simulating velocity and wall detection
+    void xthread(const void* args)
+    {
+        while (1) {
+            x_mutex.lock();
+            y_mutex.lock();
+            if (ballxvel > 0) {
+                if (maze[cursor_x_pos + 1][cursor_y_pos] != WALL_BLOCK)
+                    cursor_x_pos++;
+            } else if (ballxvel < 0) {
+                if (maze[cursor_x_pos - 1][cursor_y_pos] != WALL_BLOCK)
+                    cursor_x_pos--;
+            }
+            x_mutex.unlock();
+            y_mutex.unlock();
+            Thread::wait(100 - 98 * abs(ballxvel));
+        }
+    }
+     
+    void ythread(const void* args)
+    {
+        while (1) {
+            x_mutex.lock();
+            y_mutex.lock();
+            if (ballyvel > 0) {
+                if (maze[cursor_x_pos][cursor_y_pos + 1] != WALL_BLOCK)
+                    cursor_y_pos++;
+            } else if (ballyvel < 0) {
+                if (maze[cursor_x_pos][cursor_y_pos - 1] != WALL_BLOCK)
+                    cursor_y_pos--;
+            }
+            x_mutex.unlock();
+            y_mutex.unlock();
+            Thread::wait(100 - 98 * abs(ballyvel));
+        }
+    }
+