Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed wave_player 4DGL-uLCD-SE MMA8452
main.cpp
00001 // Project includes 00002 #include "globals.h" 00003 #include "hardware.h" 00004 #include "map.h" 00005 #include "graphics.h" 00006 #include "speech.h" 00007 #include "startmenu.h" 00008 #include "pausemenu.h" 00009 #include "gameover.h" 00010 00011 // Functions in this file 00012 int get_action (GameInputs inputs); 00013 int update_game (int action); 00014 void draw_game (int init); 00015 void init_main_map(); 00016 void init_house_map(); 00017 int main (); 00018 00019 Player p1; 00020 int omni_en = 0; 00021 int in_house; 00022 int house_enabled = false; 00023 int door_open = false; 00024 int game_over = false; 00025 int switch_axis = 0; 00026 00027 00028 /*Functions to for player to interact with the map 00029 */ 00030 00031 void interact_npc(MapItem* object){ 00032 if (p1.rock_pushed && p1.gems >= 3){ 00033 p1.quest_complete = true; 00034 } 00035 NonPlayer* n = (NonPlayer*)object -> data; 00036 if(n -> quest_requested == false){ 00037 speech("Find 3 red gems", "and move the rock", "in the backyard", "then I will give you gold!"); 00038 n -> quest_requested = true; 00039 } else if (p1.quest_complete == false){ //should quest complete be in the player struct? 00040 speech("get it boi! What", "are u waitin for?", "You must finish ", "the quest!!!!"); 00041 } else if (n -> has_key == true) { 00042 speech("Congrats!", "Thank you for", "completing the", "quest! Here's the key!"); 00043 n -> has_key = false; 00044 p1.has_key = true; 00045 } else if(n -> has_key == false){ 00046 speech("Congrats!", "Quest complete.", "", ""); 00047 } 00048 } 00049 00050 void player_hurt(){ 00051 //lower health bar 00052 p1.health+=10; 00053 for(int i = 0; i < 2; i++){ 00054 speaker.period(1.0/150.0); // 500hz period 00055 speaker =0.25; //25% duty cycle - mid range volume 00056 wait(.02); 00057 speaker=0.0; // turn off audio 00058 wait(0.1); 00059 } 00060 } 00061 00062 00063 /** 00064 * Given the game inputs, determine what kind of update needs to happen. 00065 * Possbile return values are defined below. 00066 */ 00067 #define NO_ACTION 0 00068 #define BUTTON1 1 //omni button 00069 #define BUTTON2 2 //toggle/action button 00070 #define BUTTON3 3 //scroll/select? 00071 #define MENU_BUTTON 4 00072 #define GO_LEFT 5 00073 #define GO_RIGHT 6 00074 #define GO_UP 7 00075 #define GO_DOWN 8 00076 int get_action(GameInputs inputs) 00077 { 00078 double y_axis; 00079 double x_axis; 00080 if(switch_axis){ 00081 y_axis = inputs.ax; 00082 x_axis = inputs.ay; 00083 }else{ 00084 y_axis = inputs.ay; 00085 x_axis = inputs.ax; 00086 } 00087 if(!inputs.b1){ 00088 return BUTTON1; 00089 } 00090 if(!inputs.b2){ 00091 return BUTTON2; 00092 } 00093 if (!inputs.b3){ 00094 return MENU_BUTTON; 00095 } 00096 if ((y_axis > 0.05 && y_axis < 0.9) && abs(x_axis) < .9){ 00097 return GO_LEFT; 00098 } else if ((y_axis < -0.05 && y_axis > -0.9) && abs(x_axis) < .9){ 00099 return GO_RIGHT; 00100 }else if (x_axis > 0.05 && x_axis < 0.9){ 00101 return GO_DOWN; 00102 }else if (x_axis < -0.05 && x_axis > -0.9){ 00103 return GO_UP; 00104 } 00105 return NO_ACTION; 00106 } 00107 00108 void update_npcs(){ 00109 //Map* m = get_active_map(); 00110 /*int h = map_height(); 00111 int w = map_width(); 00112 00113 for(int i = 0; i < w; i++){ 00114 for(int j = 0; j < h; j++){ 00115 if (MapItem* object = get_here(i, j)){ 00116 if (object -> type == EXTRA){ 00117 Extra* d = (Extra*)object -> data; 00118 d -> e = true; 00119 add_extra(i+1, j); 00120 } 00121 } 00122 } 00123 } 00124 for(int i = 0; i < w; i++){ 00125 for(int j = 0; j < h; j++){ 00126 if (MapItem* object = get_here(i, j)){ 00127 if (object -> type == EXTRA){ 00128 Extra* d = (Extra*)object -> data; 00129 if(d -> e == true) map_erase(i, j); 00130 } 00131 } 00132 } 00133 }*/ 00134 } 00135 00136 /** 00137 * Update the game state based on the user action. For example, if the user 00138 * requests GO_UP, then this function should determine if that is possible by 00139 * consulting the map, and update the Player position accordingly. 00140 * 00141 * Return values are defined below. FULL_DRAW indicates that for this frame, 00142 * draw_game should not optimize drawing and should draw every tile, even if 00143 * the player has not moved. 00144 */ 00145 #define NO_RESULT 0 00146 #define GAME_OVER 1 00147 #define FULL_DRAW 2 00148 #define NO_DRAW 3 00149 int update_game(int action) 00150 { 00151 // Save player previous location before updating 00152 p1.px = p1.x; 00153 p1.py = p1.y; 00154 00155 // Do different things based on the each action. 00156 // You can define functions like "go_up()" that get called for each case. 00157 switch(action) //have a function called for each type of object. Pass a pointer to the object to the interact function 00158 { 00159 case GO_UP: 00160 if (MapItem* object = get_north(p1.x, p1.y)){ 00161 //if (object -> type == NPC){ 00162 //interact_npc(object); 00163 // return NO_RESULT; 00164 if (object -> type == LBUSH){ 00165 p1.y = p1.y - 1; 00166 return NO_DRAW; 00167 } else if(object -> type == SPIKE){ 00168 player_hurt(); 00169 } else if(object -> type == GEM){ 00170 //add to gem score 00171 p1.gems++; 00172 if (p1.gems >= 3 && p1.quest_complete < 1){ 00173 p1.quest_complete += 0.5; 00174 } 00175 map_erase(p1.x, p1.y-1); 00176 } else if (!omni_en && object -> walkable == false){ 00177 return NO_RESULT; 00178 } 00179 } 00180 p1.y = p1.y - 1; 00181 return FULL_DRAW; 00182 case GO_LEFT: 00183 if (MapItem* object = get_west(p1.x, p1.y)){ 00184 if (object -> type == ROCK){ 00185 add_rock(p1.x + 2, p1.y); 00186 map_erase(p1.x+1, p1.y); 00187 p1.x = p1.x + 1; 00188 p1.rock_pushed = true; 00189 return FULL_DRAW; 00190 00191 }else if (object -> type == LBUSH){ 00192 p1.x = p1.x + 1; 00193 return NO_DRAW; 00194 }else if(object -> type == SPIKE){ 00195 player_hurt(); 00196 } else if(object -> type == GEM){ 00197 //lower health bar 00198 p1.gems++; 00199 if (p1.gems >= 3 && p1.quest_complete < 1){ 00200 p1.quest_complete += 0.5; 00201 } 00202 map_erase(p1.x+1, p1.y); 00203 }else if(object -> type == DOOR){ 00204 if (in_house){ 00205 set_active_map(0); 00206 p1.x = 3; 00207 p1.y = 7; 00208 in_house = 0; 00209 }else{ 00210 set_active_map(1); 00211 p1.x = 6; 00212 p1.y = 7; 00213 in_house = 1; 00214 } 00215 } if (!omni_en && object -> walkable == false){ 00216 return NO_RESULT; 00217 } 00218 } 00219 p1.x = p1.x + 1; 00220 return FULL_DRAW; 00221 case GO_DOWN: 00222 if (MapItem* object = get_south(p1.x, p1.y)){ 00223 if (object -> type == DOOR){ 00224 if (p1.has_key == true){ 00225 map_erase(p1.x, p1.y + 1); 00226 p1.y = p1.y + 1; 00227 door_open = true; 00228 return FULL_DRAW; 00229 } 00230 return NO_RESULT; 00231 }if (object -> type == LBUSH){ 00232 p1.y = p1.y + 1; 00233 return NO_DRAW; 00234 }else if(object -> type == SPIKE){ 00235 player_hurt(); 00236 } else if(object -> type == GEM){ 00237 //add to gem score 00238 p1.gems++; 00239 if (p1.gems >= 3 && p1.quest_complete < 1){ 00240 p1.quest_complete += 0.5; 00241 } 00242 map_erase(p1.x, p1.y+1); 00243 } 00244 if (!omni_en && object -> walkable == false){ 00245 return NO_RESULT; 00246 } 00247 } 00248 p1.y = p1.y + 1; 00249 return FULL_DRAW; 00250 00251 case GO_RIGHT: 00252 if (MapItem* object = get_east(p1.x, p1.y)){ 00253 if (object -> type == GOAL){ 00254 if(door_open == true){ 00255 game_over = true; 00256 uLCD.locate(1,1); 00257 uLCD.printf("Goal reached"); 00258 return NO_RESULT; 00259 } 00260 00261 }//else if(object -> type == GDOOR){ 00262 00263 //} //add a bit of a wait here to simulate going into the house 00264 else if(object -> type == SPIKE){ 00265 player_hurt(); 00266 00267 } if (object -> type == LBUSH){ 00268 p1.x = p1.x - 1; 00269 return NO_DRAW; 00270 }else if(object -> type == GEM){ 00271 //add to gem score 00272 p1.gems++; 00273 if (p1.gems >= 3 && p1.quest_complete < 1){ 00274 p1.quest_complete += 0.5; 00275 } 00276 map_erase(p1.x-1, p1.y); 00277 } 00278 if (!omni_en && object -> walkable == false){ 00279 return NO_RESULT; 00280 } 00281 } 00282 p1.x = p1.x - 1; 00283 return FULL_DRAW; 00284 00285 case BUTTON1: 00286 omni_en = !omni_en; 00287 break; 00288 case BUTTON2: 00289 MapItem* object1 = get_north(p1.x, p1.y); 00290 MapItem* object2 = get_south(p1.x, p1.y); 00291 MapItem* object3 = get_east(p1.x, p1.y); 00292 MapItem* object4 = get_west(p1.x, p1.y); 00293 if(object1 ->type == NPC){ 00294 interact_npc(object1); 00295 } else if (object2->type ==NPC){ 00296 interact_npc(object2); 00297 }else if (object3->type ==NPC){ 00298 interact_npc(object3); 00299 } else if (object4->type ==NPC){ 00300 interact_npc(object4); 00301 } 00302 else if (object1 ->type == GDOOR|| object2->type == GDOOR || object3 ->type == GDOOR|| object4 ->type == GDOOR){ 00303 if (p1.has_key){ 00304 door_open = true; 00305 map_erase(p1.x-1, p1.y); 00306 } else{ 00307 speech("Door Locked.", "Must get key.", "Door Locked.", "Must get key."); 00308 } 00309 } 00310 break; 00311 case MENU_BUTTON: 00312 PauseMenu pause_m(&p1); 00313 pause_m.display(); 00314 switch_axis = pause_m.get_config(); 00315 //switch_axis = ingamemenu(&p1); 00316 00317 break; 00318 default: break; 00319 } 00320 return NO_RESULT; 00321 } 00322 00323 00324 00325 /** 00326 * Entry point for frame drawing. This should be called once per iteration of 00327 * the game loop. This draws all tiles on the screen, followed by the status 00328 * bars. Unless init is nonzero, this function will optimize drawing by only 00329 * drawing tiles that have changed from the previous frame. 00330 */ 00331 void draw_game(int init) 00332 { 00333 // int param1; 00334 //int param2; 00335 // Draw game border first 00336 if(init) draw_border(); 00337 00338 // Iterate over all visible map tiles 00339 for (int i = -5; i <= 5; i++) // Iterate over columns of tiles 00340 { 00341 for (int j = -4; j <= 4; j++) // Iterate over one column of tiles 00342 { 00343 // Here, we have a given (i,j) 00344 00345 // Compute the current map (x,y) of this tile 00346 int x = i + p1.x; 00347 int y = j + p1.y; 00348 00349 // Compute the previous map (px, py) of this tile 00350 int px = i + p1.px; 00351 int py = j + p1.py; 00352 00353 // Compute u,v coordinates for drawing 00354 int u = (i+5)*11 + 3; 00355 int v = (j+4)*11 + 15; 00356 00357 // Figure out what to draw 00358 DrawFunc draw = NULL; 00359 if (init && i == 0 && j == 0 && init != NO_DRAW) // Only draw the player on init (this is when the loop hits the center of the screen) 00360 { 00361 draw_player(u, v, p1.has_key); 00362 00363 continue; 00364 } 00365 else if (x >= 0 && y >= 0 && x < map_width() && y < map_height()) // Current (i,j) in the map 00366 { 00367 MapItem* curr_item = get_here(x, y); 00368 MapItem* prev_item = get_here(px, py); 00369 if (init || curr_item != prev_item) // Only draw if they're different 00370 { 00371 if (curr_item) // There's something here! Draw it 00372 { 00373 //if (curr_item -> type == ROCK){ 00374 //set parameters 00375 // Rock* r = (Rock*) curr_item -> data; 00376 //param1 = r -> x; 00377 //param2 = r -> y; 00378 //} 00379 draw = curr_item->draw; 00380 } 00381 else // There used to be something, but now there isn't 00382 { 00383 if (in_house){ 00384 draw = draw_house_floor; 00385 }else{ 00386 draw = draw_nothing; 00387 } 00388 } 00389 } 00390 } 00391 else if (init) // If doing a full draw, but we're out of bounds, draw the walls. 00392 { 00393 draw = draw_wall; 00394 } 00395 00396 // Actually draw the tile 00397 //MapItem* curr_item = get_here(x, y); 00398 //MapItem* prev_item = get_here(px, py); 00399 if (draw){ 00400 // if(curr_item){ 00401 // if(curr_item -> type == ROCK){ 00402 // draw(param1, param2); 00403 //} 00404 //} 00405 draw(u,v); 00406 } 00407 } 00408 } 00409 00410 // Draw status bars 00411 draw_upper_status(p1.health); 00412 draw_lower_status(p1.x, p1.y); 00413 } 00414 00415 00416 /** 00417 * Initialize the main world map. Add walls around the edges, interior chambers, 00418 * and plants in the background so you can see motion. 00419 */ 00420 void init_main_map() 00421 { 00422 Map* map = set_active_map(0); 00423 // "Random" plants 00424 00425 maps_init(50, 50, 5); 00426 for(int i = map_width() + 3; i < map_area(); i += 39) 00427 { 00428 add_plant(i % map_width(), i / map_width()); 00429 } 00430 00431 srand(time(NULL)); 00432 for(int i = 0; i < 30; i++) 00433 { 00434 int x = rand()%((map_width()+1)-1) + 1; 00435 int y = rand()%((map_height()+1)-1) + 1; 00436 add_spike(x, y); 00437 } 00438 00439 for(int i = 0; i < 30; i++) 00440 { 00441 int x = rand()%((map_width()+1)-1) + 1; 00442 int y = rand()%((map_height()+1)-1) + 1; 00443 add_gem(x, y, 1); 00444 } 00445 00446 for(int i = 0; i < 15; i++) 00447 { 00448 int x = rand()%((map_width()+1)-1) + 1; 00449 int y = rand()%((map_height()+1)-1) + 1; 00450 add_gem(x, y, 2); 00451 } 00452 00453 for(int i = 0; i < 9; i++) 00454 { 00455 int x = rand()%((map_width()+1)-1) + 1; 00456 int y = rand()%((map_height()+1)-1) + 1; 00457 add_gem(x, y, 3); 00458 } 00459 00460 pc.printf("plants\r\n"); 00461 00462 p1.x = 41; 00463 p1.y = 10; 00464 pc.printf("Adding walls!\r\n"); 00465 add_wall(0, 0, HORIZONTAL, map_width()); 00466 add_wall(0, map_height()-1, HORIZONTAL, map_width()); 00467 add_wall(0, 0, VERTICAL, map_height()); 00468 add_wall(map_width()-1, 0, VERTICAL, map_height()); 00469 add_rock(13, 2); 00470 add_redhouse(9, 1, 1); 00471 add_bush_rect(1, 19, 11, 38); 00472 add_bush_rect(20, 17, 23, 21); 00473 pc.printf("Walls done!\r\n"); 00474 00475 print_map(); 00476 } 00477 00478 void init_house_map() 00479 { 00480 00481 Map* map = set_active_map(1); //one is a house map 00482 //in_house = 1; 00483 maps_init(10, 10, 5); 00484 add_wall(0, 0, HORIZONTAL, map_width()); 00485 add_wall(0, map_height()-1, HORIZONTAL, map_width()); 00486 add_wall(0, 0, VERTICAL, map_height()); 00487 add_wall(map_width()-1, 0, VERTICAL, map_height()); 00488 00489 add_wall(1, 4, HORIZONTAL, 3); 00490 add_wall(4, 4, VERTICAL, 4); 00491 add_gdoor(4,8); 00492 00493 add_npc(6, 2); //place NPC in the house 00494 add_door(8, 8); 00495 add_goal(1, 8); 00496 } 00497 00498 /** 00499 * Program entry point! This is where it all begins. 00500 * This function orchestrates all the parts of the game. Most of your 00501 * implementation should be elsewhere - this holds the game loop, and should 00502 * read like a road map for the rest of the code. 00503 */ 00504 int main() 00505 { 00506 00507 StartMenu start_m = StartMenu(); 00508 int st = start_m.display(); 00509 // First things first: initialize hardware 00510 ASSERT_P(hardware_init() == ERROR_NONE, "Hardware init failed!"); 00511 00512 // Initialize the maps 00513 00514 init_house_map(); 00515 init_main_map(); 00516 00517 00518 // Initialize game state 00519 //set_active_map(0); //this doesn't need to be here twice 00520 p1.health = 0; 00521 p1.lives = 3; 00522 p1.x = p1.y = 5; 00523 p1.quest_complete = false; 00524 00525 // Initial drawing 00526 draw_game(true); 00527 00528 // Main game loop 00529 while(p1.lives) 00530 { 00531 // Timer to measure game update speed 00532 Timer t; t.start(); 00533 00534 // Actually do the game update: 00535 // 1. Read inputs 00536 GameInputs in = read_inputs(); 00537 // 2. Determine action (get_action) 00538 int a = get_action(in); 00539 // 3. Update game (update_game) 00540 int u = update_game(a); 00541 update_npcs(); 00542 // 3b. Check for game over 00543 draw_game(u); 00544 if (p1.health >= 120){ 00545 int result = gameover(--p1.lives); 00546 if (result){ 00547 init_main_map(); 00548 p1.health = 0; 00549 //Player.lives--; 00550 p1.x = p1.y = 5; 00551 p1.quest_complete = false; 00552 }} 00553 if (game_over == true){ 00554 break; 00555 } 00556 00557 //else if(house_enabled == true){ 00558 00559 //Player.x = Player.y = 5; //idk if this should be here... 00560 //} 00561 // 4. Draw frame (draw_game) 00562 00563 00564 00565 // 5. Frame delay 00566 t.stop(); 00567 int dt = t.read_ms(); 00568 if (dt < 100) wait_ms(100 - dt); 00569 } 00570 draw_game_over(); 00571 }
Generated on Fri Jul 15 2022 03:29:10 by
