ELEC2645 (2018/19) / Mbed 2 deprecated el17lw

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Engine.cpp Source File

Engine.cpp

00001 #include "Engine.h"
00002 
00003 // Reference for the technique used to generate random numbers.
00004 // [1] "rand" cplusplus. [Online] Available: 
00005 // http://www.cplusplus.com/reference/cstdlib/rand/ [Accessed: 22 April 2019]. 
00006 
00007 // Buffer to print updated score.
00008 char buffer[14];   
00009 
00010 // Constructor and destructor.
00011 Engine::Engine() {} 
00012 
00013 Engine::~Engine() {}
00014 
00015 void Engine::init() {
00016   // Reset functions are used for init.
00017   reset_skater();
00018   reset_engine();
00019   srand(time(NULL));  // Set up for generating random numbers, [1].
00020 }
00021 
00022 void Engine::check_reset(N5110 &lcd, Gamepad &gamepad) {
00023   // If reset flag is true, end and restart the game.
00024   if (_skater.get_reset_flag()) {
00025     gamepad.leds_on();
00026     execute_dying_sequence(lcd, gamepad);
00027     wait(1);  // Short pause.
00028     reset_skater();
00029     reset_engine();
00030   }
00031 }
00032 
00033 void Engine::execute_dying_sequence(N5110 &lcd, Gamepad &gamepad) {
00034   // Player has died and game needs to restart, printing their score.
00035   wait(1);  // Short pause.
00036   gamepad.leds_off();
00037   lcd.clear();
00038   for (int i = 0; i < 40; i = i + 8) {  // Counter for y direction, sweeps top 
00039   // to bottom.
00040     for (int j = 0; j < 84; j++) {  // Counter for x direction, sweeps L to R. 
00041       lcd.setPixel(j,i,true);
00042       lcd.setPixel(i,j,true);
00043       lcd.printString("TRY AGAIN",30,5);  
00044       lcd.refresh();
00045       gamepad.tone(int(1099 - 15.4*j - 1.2*i), 0.05);  // Frequency of tone is 
00046       // dependent on counters.
00047       wait(0.001);  // Control speed of the sequence.
00048       sprintf(buffer,"%2d",_player_score); 
00049       lcd.printString(buffer,0,5);
00050     }  
00051   }
00052 }
00053 
00054 void Engine::reset_skater() {
00055   // Initial values for skater.
00056   _skater_direction = Left;
00057   _start_platform_flag = true;  // For printing start text in EngineController.
00058   _skater.set_reset_flag(false);
00059   _moving_counter = 0;
00060   _jump_counter = 20;  // Start game falling onto the platform. 
00061   _fall_flag = false;
00062 }  
00063 
00064 void Engine::reset_engine() {
00065   // Inital values for engine (and gamepad input).
00066   _input.coord.x = 0;
00067   _input.coord.y = 0;
00068   _input.A_flag = false;
00069   _lower_platforms.init(40);  // 40 is the platform y coord.
00070   _upper_platforms.init(22);  // 22 is the platform y coord.
00071   _coin.init();
00072   _fire.init();
00073   _coin_collision_flag = false;
00074   _player_score = 0;
00075   _fire_height = 0;
00076 }  
00077 
00078 void Engine::read_input(Gamepad &gamepad) {
00079   // Set up the input struct for use.
00080   _input.coord = gamepad.get_mapped_coord(); 
00081   _input.A_flag = gamepad.check_event(Gamepad::A_PRESSED);
00082 } 
00083 
00084 void Engine::process_y(Gamepad &gamepad) {
00085   // Sets the y coord by first checking if the skater should be falling.
00086   set_fall_flag();  // Update the fall flag dependent on skater position.
00087   if (_fall_flag) {
00088     _skater.fall(_fall_flag, gamepad);  // Fall if the skater should be.
00089   } else {
00090     _skater.set_y_position(_input.A_flag, _jump_counter, _level_condition, 
00091                            gamepad);
00092   }
00093   _fall_flag = _skater.get_fall_flag();  // Update fall flag.
00094   _skater_y = _skater.get_y_position();
00095   _jump_counter = _skater.get_jump_counter();  // Update jump counter.
00096 }
00097 
00098 void Engine::set_fall_flag() {
00099   // Set the fall flag to true if the skater is not on one of the lower 
00100   // platforms. The start platform condition has been offset by 6 to account for 
00101   // skater sprite size.
00102   // If the skater is between platform 1 and 2, and on the lower level. 
00103   if (((_lower_line_1.x_end < _skater_x) 
00104       && (_skater_x < (_lower_line_2.x_start - 6)))  
00105       && _skater_y == 23) {  
00106     _fall_flag = true; 
00107   // If the skater is between platforms 2 and 3, and on the lower level.  
00108   } else if (((_lower_line_2.x_end < _skater_x) 
00109              && (_skater_x < (_lower_line_3.x_start - 6))) 
00110              && _skater_y == 23) {
00111     _fall_flag = true;
00112   // If the skater is between platforms 3 and 1, and on the lower level.  
00113   } else if (((_lower_line_3.x_end < _skater_x) 
00114              && (_skater_x < (_lower_line_1.x_start - 6))) 
00115              && _skater_y == 23) {
00116     _fall_flag = true;
00117   }   
00118 }
00119     
00120 void Engine::process_x(int game_counter) {
00121   // Sets the x coord from input.
00122   _skater.set_x_position_and_sprite(_input.coord.x, 
00123     _moving_counter, 
00124     _skater_direction,
00125     _input.coord.y);
00126   _skater_x = _skater.get_x_position();
00127   _moving_counter = _skater.get_moving_counter();  // Update moving counter.
00128   _speed_divider = int(-0.05*_player_score + 4);  // Speed divider is calculated
00129   // from player score.
00130   // Move the skater along with platforms at rate determined by speed divider if
00131   // the skater is not moving left.
00132   if ((game_counter % _speed_divider == 0) && (_input.coord.x > -0.1)) {  
00133     _moving_counter--;
00134   }
00135 }
00136     
00137 void Engine::process_sprite() {
00138   // Update the sprite and direction.
00139   _skater_sprite = _skater.get_sprite_value();
00140   _skater_direction = _skater.get_direction();
00141 }
00142 
00143 
00144 void Engine::set_level_condition() {
00145   // If the skater is under or on top of any of the upper platforms, set
00146   // level condition to 1. 
00147   // Offset of 6 is to account for sprite size.
00148   // If the skater is between start and end of upper platform 1.  
00149   if (((_upper_line_1.x_start - 6) <= _skater_x) 
00150       && (_skater_x <= _upper_line_1.x_end)) {
00151     _level_condition = 1; 
00152   // If the skater is between start and end of upper platform 2. 
00153   } else if (((_upper_line_2.x_start - 6) <= _skater_x) 
00154              && (_skater_x <= _upper_line_2.x_end)) {
00155     _level_condition = 1;
00156   // If the skater is between start and end of upper platform 3.   
00157   } else if (((_upper_line_3.x_start - 6) <= _skater_x) 
00158              && (_skater_x <= _upper_line_3.x_end)) {
00159     _level_condition = 1;
00160   } else {
00161     _level_condition = 0;
00162   }   
00163 }
00164     
00165 void Engine::generate_level(int game_counter) {
00166   // Generate properties for the level.
00167   generate_lower_lines();
00168   generate_upper_lines();
00169   _coin.generate_coin();
00170   generate_fire(game_counter);
00171 }
00172 
00173 void Engine::draw_screen_fire(int game_counter, N5110 &lcd) {
00174   // Prints the dynamic fire at the bottom of the screen.
00175   // Restricts the max fire height multiplier, which is dependent on player 
00176   // score. Fire will start when score = 3.
00177   if (_player_score < 15) {
00178     _fire_height = _player_score;
00179   } else {
00180     _fire_height = 14;
00181   }
00182   // i corresponds to horizontal positions of pixels.
00183   for (int i = 1; i < 84; i++) {
00184     if (i % 4 == 0) {
00185       // j corresponds to vertical height of pixels, and the max height is
00186       // dependent on game counter (0 to 99) so changes every loop, and is 
00187       // scaled.
00188       for (int j = 0; j < game_counter*0.01*_fire_height; j++) {
00189         lcd.setPixel(i + (rand() % 8 + 1) ,50 - j*1.3,true);  // Horizontal 
00190         // position of pixel is constrained random [1], multiplier on j varies 
00191         // local height. 
00192         lcd.setPixel(i - (rand() % 8 + 1) ,50 - j*1.2,true);  // [1].
00193         lcd.setPixel(i - (rand() % 8 + 1) ,50 - j*1.6,true);  // [1].
00194         lcd.setPixel(i + (rand() % 8 + 1) ,50 - j*1.1,true);  // [1].
00195         lcd.setPixel(i - (rand() % 8 + 1) ,50 - j*1.4,true);  // [1].
00196       }  
00197     }
00198   }    
00199 }
00200 
00201 void Engine::generate_lower_lines() {
00202   // Use a scaled random number to generate the length of the lower lines.
00203   _length_1 = (rand() %20) + 10;  // [1].   
00204   _lower_platforms.set_line_1(_length_1);
00205   _lower_line_1 = _lower_platforms.get_line_1(); 
00206   _length_2 = (rand() %20) + 10;  // [1].      
00207   _lower_platforms.set_line_2(_length_2);
00208   _lower_line_2 = _lower_platforms.get_line_2();
00209   _length_3 = (rand() %20) + 10;  // [1].      
00210   _lower_platforms.set_line_3(_length_3);
00211   _lower_line_3 = _lower_platforms.get_line_3();
00212 }
00213 
00214 void Engine::generate_upper_lines() {   
00215   // Set the length of the upper lines to be proportionally smaller to
00216   // the length of the lower lines.
00217   _upper_platforms.set_line_1(_length_1 / 2);
00218   _upper_line_1 = _upper_platforms.get_line_1();       
00219   _upper_platforms.set_line_2(_length_2 / 2);
00220   _upper_line_2 = _upper_platforms.get_line_2();  
00221   _upper_platforms.set_line_3(_length_3 / 2);
00222   _upper_line_3 = _upper_platforms.get_line_3();
00223 }
00224 
00225 void Engine::generate_fire(int game_counter) {
00226   // Generates the x and y coordinate of the fire. Y oscillates from 5 to 23.
00227   _fire.generate_fire(); // Generates X coord of fire.
00228   // Y is calculated from parabolic relation to game counter.
00229   _fire_y = int(-0.0073*game_counter*game_counter + 0.73*game_counter + 5);  
00230 }
00231 
00232 void Engine::update_lcd(N5110 &lcd, int game_counter){
00233   // Draw all sprites, screen fire, platforms and player score. 
00234   lcd.drawSprite(_skater_x,_skater_y,17,10,
00235                 (int *)_skater.get_sprite(_skater_sprite));
00236   lcd.drawSprite(_coin.get_coin_x(),_coin.get_coin_y(),5,5,
00237                  (int*)_coin.get_coin_sprite());
00238   lcd.drawSprite(_fire.get_fire_x(),_fire_y,5,8,(int*)_fire.get_fire_sprite()); 
00239   lcd.drawLine(_lower_line_2.x_start,_lower_line_2.y,_lower_line_2.x_end,
00240                _lower_line_2.y,FILL_BLACK);
00241   lcd.drawLine(_lower_line_1.x_start,_lower_line_1.y,_lower_line_1.x_end,
00242                _lower_line_1.y,FILL_BLACK);
00243   lcd.drawLine(_lower_line_3.x_start,_lower_line_3.y,_lower_line_3.x_end,
00244                _lower_line_3.y,FILL_BLACK);
00245   lcd.drawLine(_upper_line_2.x_start,_upper_line_2.y,_upper_line_2.x_end,
00246                _upper_line_2.y,FILL_BLACK);
00247   lcd.drawLine(_upper_line_1.x_start,_upper_line_1.y,_upper_line_1.x_end,
00248                _upper_line_1.y,FILL_BLACK);
00249   lcd.drawLine(_upper_line_3.x_start,_upper_line_3.y,_upper_line_3.x_end,
00250                _upper_line_3.y,FILL_BLACK);
00251   // Print the score.
00252   sprintf(buffer,"%2d",_player_score);
00253   lcd.printString(buffer,0,0);
00254   draw_screen_fire(game_counter, lcd);
00255 }
00256 
00257 bool Engine::get_start_platform_flag() {
00258   if (_input.A_flag) _start_platform_flag = false;  // Makes starting platform 
00259   // vanish after first jump of the game.
00260   return _start_platform_flag;
00261 }
00262 
00263 void Engine::check_coin_collision(Gamepad &gamepad) {
00264   // If skater x and y coord matches the coin's. Small adjustment for Y coord
00265   // compensates for skater sprite size.
00266   if (_skater_x == _coin.get_coin_x() 
00267       && (_skater_y == _coin.get_coin_y() - 10)) {  
00268     _coin_collision_flag = true;
00269     _player_score++;
00270     _coin.set_coin((rand() % 100),(abs(rand() % 100 - 20)));  // Place coin 
00271     // on a constrained random position, [1].
00272     gamepad.tone(1500, 0.05);  // Make collection noise on buzzer.
00273     wait(0.05);
00274     gamepad.tone(3000, 0.05);   
00275   }
00276 }
00277 
00278 void Engine::check_fire_collision(Gamepad &gamepad, int game_counter) {
00279   // If skater is not ducking, has same x coord and within a range of y coord 
00280   // as fire.
00281   if (_input.coord.y > -0.1 
00282       && _skater_x == _fire.get_fire_x() 
00283       && _skater_y > _fire_y - 10 
00284       && _skater_y < _fire_y + 10
00285       ) {  // A range of Y coords to make collision 
00286   // more frequent.
00287     _skater.set_reset_flag(true);
00288     gamepad.tone(400, 0.25); // Make collision noise on buzzer.
00289     wait(0.05);
00290     gamepad.tone(200, 0.25);
00291   } else if ( _skater_x < -10 || _skater_x > 84 ) { // If skater goes off the 
00292   // screen.
00293     _skater.set_reset_flag(true);
00294     gamepad.tone(200, 0.5);
00295   }
00296   // If the skater collides with the scaled peak of the background fire. 
00297   if (_skater_y > (50 - game_counter*_fire_height*0.023)) {
00298     _fall_flag = true;
00299     wait(0.05);  // Slow down falling sequence. 
00300   } 
00301 }
00302 
00303 int Engine::get_player_score() {
00304   return _player_score;
00305 }
00306