tao lao
Dependencies: mbed wave_player 4DGL-uLCD-SE MMA8452
main.cpp
- Committer:
- hnguyen403
- Date:
- 2020-11-24
- Revision:
- 3:33bf11645fe1
- Parent:
- 2:4947d6a82971
File content as of revision 3:33bf11645fe1:
//================================================================= // The main program file. // // Copyright 2020 Georgia Tech. All rights reserved. // The materials provided by the instructor in this course are for // the use of the students currently enrolled in the course. // Copyrighted course materials may not be further disseminated. // This file must not be made publicly available anywhere. //================================================================== // Project includes #include "globals.h" #include "hardware.h" #include "map.h" #include "graphics.h" #include "snake.h" #include "mbed.h" //#include "wave_player.h" #include "SDFileSystem.h" #include <math.h> #include<stdio.h> #define CITY_HIT_MARGIN 1 #define CITY_UPPER_BOUND (SIZE_Y-(LANDSCAPE_HEIGHT+MAX_BUILDING_HEIGHT)) int go_right(int x, int y); int go_left(int x, int y); int go_up(int x, int y); int go_down(int x, int y); // Helper function declarations void playSound(char* wav); /** * The main game state. Must include snake locations and previous locations for * drawing to work properly. Other items can be added as needed. */ /** * Given the game inputs, determine what kind of update needs to happen. * Possbile return values are defined below. */ Snake snake; // Function prototypes /** * Given the game inputs, determine what kind of update needs to happen. * Possible return values are defined below. */ #define NO_RESULT 0 #define NO_ACTION 0 #define ACTION_BUTTON 1 #define MENU_BUTTON 2 #define GO_LEFT 3 #define GO_RIGHT 4 #define GO_UP 5 #define GO_DOWN 6 #define GAME_OVER 7 #define FULL_DRAW 8 #define WON 9 #define FOODN 10 #define FOODS 11 #define FOODW 12 #define FOODE 13 // Get Actions from User (push buttons & accelerometer) // Based on push button and accelerometer inputs, determine which action // needs to be performed (may be no action). int get_action(GameInputs inputs) { MapItem* N=get_north(snake.head_x,snake.head_y); MapItem* S=get_south(snake.head_x,snake.head_y); MapItem* W=get_east(snake.head_x, snake.head_y); MapItem* E=get_west(snake.head_x, snake.head_y); if (E->type==WALL || N->type==WALL || S->type==WALL ||W->type==WALL) return GAME_OVER; if (inputs.ay >= 0.20) return GO_UP; if (inputs.ay < -0.20) return GO_DOWN; if (inputs.ax < -0.20) return GO_LEFT; if (inputs.ax >= 0.20) return GO_RIGHT; else return NO_ACTION; } /** * Update the game state based on the user action. For example, if the user * requests GO_UP, then this function should determine if that is possible by * consulting the map, and update the snake position accordingly. * * Return values are defined below. FULL_DRAW indicates that for this frame, * draw_game should not optimize drawing and should draw every tile, even if * the snake has not moved. */ int update_game(int action) { snake.head_px = snake.head_x; snake.head_py = snake.head_y; switch(action) { case GO_UP: snake.head_y -= 1; for (int i = 1; i < snake.length-1; i++){ int oldx = snake.head_px; int oldy = snake.head_py; int temx = snake.locations[i].x; int temy = snake.locations[i].y; snake.locations[i].x = oldx; snake.locations[i].y = oldy; oldx = temx; oldy = temy;} if (get_north(snake.head_x,snake.head_y)->type == GOODIE) {map_erase(snake.head_x,snake.head_y-1); return FULL_DRAW;} break; case GO_LEFT: snake.head_x -= 1; for (int i = 1; i < snake.length-1; i++){ int oldx = snake.head_px; int oldy = snake.head_py; int temx = snake.locations[i].x; int temy = snake.locations[i].y; snake.locations[i].x = oldx; snake.locations[i].y = oldy; oldx = temx; oldy = temy;} if (get_west(snake.head_x-1,snake.head_y)->type == GOODIE) {map_erase(snake.head_x,snake.head_y); return FULL_DRAW;} break; case GO_DOWN: snake.head_y += 1; for (int i = 1; i < snake.length-1; i++){ int oldx = snake.head_px; int oldy = snake.head_py; int temx = snake.locations[i].x; int temy = snake.locations[i].y; snake.locations[i].x = oldx; snake.locations[i].y = oldy; oldx = temx; oldy = temy;} if (get_south(snake.head_x,snake.head_y+1)->type == GOODIE) {map_erase(snake.head_x,snake.head_y); return FULL_DRAW;} break; case GO_RIGHT: snake.head_x += 1; for (int i = 1; i < snake.length-1; i++){ int oldx = snake.head_px; int oldy = snake.head_py; int temx = snake.locations[i].x; int temy = snake.locations[i].y; snake.locations[i].x = oldx; snake.locations[i].y = oldy; oldx = temx; oldy = temy;} if (get_here(snake.head_x,snake.head_y)->type == GOODIE) {add_nothing(snake.head_x,snake.head_y); draw_snake_head(snake.head_x,snake.head_y); snake.score= snake.score + 1;} break; case GAME_OVER: {uLCD.color(RED); uLCD.cls(); uLCD.text_width(3); uLCD.text_height(3); uLCD.printf("GAME\nOVER"); uLCD.color(GREEN); uLCD.text_width(1); uLCD.text_height(1); uLCD.printf("\n\n\n\n\nScore %d", snake.score); uLCD.color(GREEN);} while(1 == 1); } return NO_RESULT; } /** * Draw the upper status bar. */ void draw_upper_status() { uLCD.line(0, 9, 127, 9, GREEN); } /** * Draw the lower status bar. */ void draw_lower_status() { uLCD.line(0, 118, 127, 118, GREEN); } /** * Draw the border for the map. */ void draw_border() { uLCD.filled_rectangle(0, 9, 127, 14, WHITE); // Top uLCD.filled_rectangle(0, 13, 2, 114, WHITE); // Left uLCD.filled_rectangle(0, 114, 127, 117, WHITE); // Bottom uLCD.filled_rectangle(124, 14, 127, 117, WHITE); // Right } /** * Entry point for frame drawing. This should be called once per iteration of * the game loop. This draws all tiles on the screen, followed by the status * bars. Unless init is nonzero, this function will optimize drawing by only * drawing tiles that have changed from the previous frame. */ void draw_game(int draw_option) { // Draw game border first if(draw_option == FULL_DRAW) { draw_border(); int u = 58; int v = 59; draw_snake_head(u, v); draw_snake_body(u-11, v); draw_snake_tail(u-22, v); return; } // Iterate over all visible map tiles for (int i = -5; i <= 5; i++) { // Iterate over columns of tiles for (int j = -4; j <= 4; j++) { // Iterate over one column of tiles // Here, we have a given (i,j) // Compute the current map (x,y) of this tile int x = i + snake.head_x; int y = j + snake.head_y; // Compute the previous map (px, py) of this tile int px = i + snake.head_px; int py = j + snake.head_py; // Compute u,v coordinates for drawing int u = (i+5)*11 + 3; int v = (j+4)*11 + 15; // Figure out what to draw DrawFunc draw = NULL; if (x >= 0 && y >= 0 && x < map_width() && y < map_height()) { // Current (i,j) in the map MapItem* curr_item = get_here(x, y); MapItem* prev_item = get_here(px, py); if (draw_option || curr_item != prev_item) { // Only draw if they're different if (curr_item) { // There's something here! Draw it draw = curr_item->draw; } else { // There used to be something, but now there isn't draw = draw_nothing; } } else if (curr_item && curr_item->type == CLEAR) { // This is a special case for erasing things like doors. draw = curr_item->draw; // i.e. draw_nothing } } else if (draw_option) { // If doing a full draw, but we're out of bounds, draw the walls. draw = draw_wall; } // Actually draw the tile if (draw) draw(u, v); } } // Draw status bars draw_upper_status(); draw_lower_status(); } /** * Initialize the main world map. Add walls around the edges, interior chambers, * and plants in the background so you can see motion. */ void init_main_map() { uLCD.text_width(1); uLCD.text_height(1); uLCD.printf("Score %d", snake.score); uLCD.color(GREEN); // "Random" plants Map* map = set_active_map(0); for(int i = map_width() + 3; i < map_area(); i += 39) { add_goodie(i % map_width(), i / map_width()); } pc.printf("plants\r\n"); pc.printf("Adding walls!\r\n"); add_wall(0, 0, HORIZONTAL, map_width()); add_wall(0, map_height()-1, HORIZONTAL, map_width()); add_wall(0, 0, VERTICAL, map_height()); add_wall(map_width()-1, 0, VERTICAL, map_height()); pc.printf("Walls done!\r\n"); add_snake_head(snake.locations[0].x, snake.locations[0].y); add_snake_body(snake.locations[1].x, snake.locations[1].y); add_snake_tail(snake.locations[2].x, snake.locations[2].y); pc.printf("Add extra chamber\r\n"); add_wall(30, 0, VERTICAL, 10); add_wall(30, 10, HORIZONTAL, 10); add_wall(39, 0, VERTICAL, 10); pc.printf("Added!\r\n"); // Add stairs to chamber (map 1) //add_stairs(15, 5, 1, 5, 5); // profile_hashtable(); print_map(); } /** * Program entry point! This is where it all begins. * This function or all the parts of the game. Most of your * implementation should be elsewhere - this holds the game loop, and should * read like a road map for the rest of the code. */ int main() { // First things first: initialize hardware ASSERT_P(hardware_init() == ERROR_NONE, "Hardware init failed!"); snake_init(&snake); // 0. Initialize the maps -- implement this function: maps_init(); init_main_map(); playSound("/sd/wavfiles/track.wav"); // Initialize game state set_active_map(0); snake.head_x = snake.head_y = 5 ; // Initial drawing draw_game(FULL_DRAW); // Main game loop while(1) { // Timer to measure game update speed Timer t; t.start(); // 1. Read inputs -- implement this function: GameInputs inputs = read_inputs(); // 2. Determine action (move, act, menu, etc.) -- implement this function: int action = get_action(inputs); // 3. Update game -- implement this function: int result = update_game(action); // 3b. Check for game over based on result // and if so, handle game over -- implement this. // 4. Draw screen -- provided: draw_game(result); // Compute update time t.stop(); int dt = t.read_ms(); // Display and wait // NOTE: Text is 8 pixels tall if (dt < 100) wait_ms(100 - dt); } } // Plays a wavfile void playSound(char* wav) { }