This is a ball on the Mbed.
Dependencies: 4DGL-uLCD-SE IMUfilter ITG3200 Music mbed-rtos mbed
main.cpp
- Committer:
- Strikewolf
- Date:
- 2014-03-14
- Revision:
- 0:680348a938f8
File content as of revision 0:680348a938f8:
#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)); } }