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.
Revision 38:a85bc227b907, committed 2019-05-09
- Comitter:
- JamesCummins
- Date:
- Thu May 09 01:09:18 2019 +0000
- Parent:
- 37:de1f584bce71
- Child:
- 39:dfc489594f11
- Commit message:
- Doxygen documentation written out and in line commenting completed. Game working and finished. Tests.h still to write out
Changed in this revision
--- a/Ball/Ball.cpp Mon May 06 21:44:49 2019 +0000
+++ b/Ball/Ball.cpp Thu May 09 01:09:18 2019 +0000
@@ -8,16 +8,16 @@
void Ball::init(int radius){
_radius = radius;
- _x = 42;
+ _x = 42; //start ball in the centre of the screen
_y = 24;
- _velocity.x = 0;
- _velocity.y = 0;
- _ball_speed = 5;
+ _velocity.x = 0; //initially have the velocity as 0 until the
+ _velocity.y = 0; //accelerometer senses otherwise
+ _ball_speed = 5; //medium sensitivity to tilt input
}
void Ball::draw(N5110 &lcd){
int radius = get_radius();
- lcd.drawCircle(_x, _y, radius, FILL_BLACK);
+ lcd.drawCircle(_x, _y, radius, FILL_BLACK); //draw black circle at coord (x, y) with preset radius
}
void Ball::read_input(FXOS8700CQ &accelerometer){
@@ -30,49 +30,49 @@
void Ball::update(){
int RADIUS = get_radius();
- _x += _velocity.x;
+ _x += _velocity.x; //update position based on how much tilt inputted
_y += _velocity.y;
- if (_x < RADIUS){ _x = RADIUS;} //check wall collisions
- if (_x > 84 - RADIUS){ _x = 83 - RADIUS;}
- if (_y < RADIUS){ _y = RADIUS;}
- if (_y > 48 - RADIUS){ _y = 47 - RADIUS;}
+ if (_x < RADIUS){ _x = RADIUS;} //check wall collisions
+ if (_x > 84 - RADIUS){ _x = 83 - RADIUS;} //if ball position is going to
+ if (_y < RADIUS){ _y = RADIUS;} //exceed boundaries of the screen
+ if (_y > 48 - RADIUS){ _y = 47 - RADIUS;} //then fix it to the edge of the screen
printf("ball speed = %d\n", _ball_speed);
}
Vector2D Ball::get_position(){
- Vector2D pos = {_x, _y};
+ Vector2D pos = {_x, _y}; //combine x and y into Vector2D
return pos;
}
Vector2D Ball::get_velocity(){
- Vector2D vel = {_velocity.x, _velocity.y};
+ Vector2D vel = {_velocity.x, _velocity.y}; //combine velocity.x and .y into a Vector2D
return vel;
}
int Ball::get_radius(){
- int radius = _radius;
+ int radius = _radius; //find from private member variable
return radius;
}
int Ball::get_ball_speed(){
- int ball_speed = _ball_speed;
+ int ball_speed = _ball_speed; //find from private member variable
return ball_speed;
}
void Ball::set_ball_speed(int ball_speed){
- _ball_speed = ball_speed;
+ _ball_speed = ball_speed; //update private member variable with user input
}
void Ball::set_velocity(Vector2D vel){
- _velocity.x = vel.x;
- _velocity.y = vel.y;
+ _velocity.x = vel.x; //must pass each part of the struct individually,
+ _velocity.y = vel.y; //can't pass both at once
}
void Ball::set_position(Vector2D pos){
- _x = pos.x;
+ _x = pos.x; //as with set_velocity
_y = pos.y;
}
void Ball::set_radius(int radius){
- _radius = radius;
+ _radius = radius; //don't use in code, other than initially where radius is defined using #define in main.cpp
}
\ No newline at end of file
--- a/Ball/Ball.h Mon May 06 21:44:49 2019 +0000
+++ b/Ball/Ball.h Thu May 09 01:09:18 2019 +0000
@@ -6,6 +6,64 @@
#include "Gamepad.h"
#include "FXOS8700CQ.h"
+/**Ball Class
+@brief Library for creating a ball and moving it round a pre-defined area.
+@brief The library also implements drawing the ball on an LCD display
+
+@author James Cummins
+
+@code
+
+#include "mbed.h"
+#include "ball.h"
+#define RADIUS 3
+
+Ball ball;
+FXOS8700CQ accelerometer(I2C_SDA,I2C_SCL);
+N5110 lcd(PTC9,PTC0,PTC7,PTD2,PTD1,PTC11);
+Gamepad gamepad;
+
+int main(){
+ ball.init(RADIUS); //first must initialise the ball with its radius
+
+ //can check what radius we've initialised with...
+ int radius = ball.get_radius();
+
+ //...and change it if preferred
+ radius = 5;
+ ball.set_radius(radius);
+
+ //Check the current sensitivity of the ball to input motion
+ int sensitivity = ball.get_ball_speed();
+
+ //and can set it to a different value to cause greater movement for the
+ //same degree of tilt in the gamepad
+ sensitivity = 3;
+ ball.set_ball_speed(sensitivity);
+
+ //read_input, update and draw combine to monitor an input and display the
+ //subsequent output changes on an LCD display
+ ball.read_input(accelerometer);
+ ball.update();
+
+ //Can read the ball's position and velocity into Vector2D structs
+ Vector2D coords = ball.get_position();
+ Vector2D vel = ball.get_velocity();
+
+ if(coords.x > 80){ coords.x = 80; }
+ if(vel.y > 5){ vel.y = 5; }
+
+ //Passing a Vector2D into set_position or set_velocity
+ //moves the ball to a new desired location or at a new speed
+ ball.set_position(coords);
+ ball.set_velocity(vel);
+
+ ball.draw(lcd);
+}
+
+@endcode
+*/
+
class Ball {
--- a/BrickBreaker_Engine/BrickBreakerEngine.cpp Mon May 06 21:44:49 2019 +0000
+++ b/BrickBreaker_Engine/BrickBreakerEngine.cpp Thu May 09 01:09:18 2019 +0000
@@ -12,122 +12,120 @@
void BrickBreakerEngine::init(int radius, Ball &ball){
_ball_radius = radius;
ball.init(_ball_radius);
- srand(time(NULL));
- _square_coord.x = 2 + rand()%80;
+ srand(time(NULL)); //first square will be the same each time
+ _square_coord.x = 2 + rand()%80; //but is randomly generated by random noise thereafter
_square_coord.y = 8 + rand()%36;
}
-//Method for rendering
-
-void BrickBreakerEngine::brickbreaker_draw(N5110 &lcd, Ball &ball){
- ball.draw(lcd);
- lcd.drawRect(_square_coord.x, _square_coord.y, 5, 5, FILL_BLACK);
- print_score(lcd);
-}
-
/////////////Brickbreaker functionality/////////////////////
+void BrickBreakerEngine::brickbreaker_draw(N5110 &lcd, Ball &ball){
+ ball.draw(lcd); //draw ball
+ lcd.drawRect(_square_coord.x, _square_coord.y, 5, 5, FILL_BLACK); //draw randomly generated square
+ print_score(lcd); //draw score in corner
+}
+
void BrickBreakerEngine::set_score(int score){
- _score = score;
+ _score = score; //used to initialise score upon restart
}
void BrickBreakerEngine::generate_rand_square(AnalogIn &randnoise){
- int rand = randnoise.read_u16();
- Vector2D square_coords = {rand % 80, 8 + rand % 36};
- _square_coord = square_coords;
+ int rand = randnoise.read_u16(); //noise on unconnected ADC channel expanded to 16 bit int
+ Vector2D square_coords = {rand % 80, 8 + rand % 36}; //offset by 8 so it doesn't overlap the score
+ _square_coord = square_coords; //update the square coordinates for rendering
}
void BrickBreakerEngine::check_square_collision(AnalogIn &randnoise, Ball &ball){
int radius = ball.get_radius();
Vector2D position = ball.get_position();
- if (abs(position.x - (_square_coord.x + 2)) <= (radius + 2) and
- abs(position.y - (_square_coord.y + 2)) <= (radius + 2)) {
- _score++;
- generate_rand_square(randnoise);
+ if (abs(position.x - (_square_coord.x + 2)) <= (radius + 2) and //adding 2 to square coords gives the centre of the square
+ abs(position.y - (_square_coord.y + 2)) <= (radius + 2)) { // <= radius+2 checks that edges aren't touching rather than centres of each
+ _score++; //increment score if collision
+ generate_rand_square(randnoise); //generate new square
}
}
void BrickBreakerEngine::print_score(N5110 &lcd){
char buffer[2];
int score = _score;
- sprintf(buffer, "%d", score);
- lcd.printString(buffer, 72, 0);
+ sprintf(buffer, "%d", score); //use sprintf so that a variable (rather than a constant) can be use in printString.
+ lcd.printString(buffer, 72, 0); //print in top right corner of the screen
}
void BrickBreakerEngine::read_high_scores(){
- FILE *fp;
- fp = fopen("/sd/bbhighscores.txt", "r");
+ FILE *fp; //open file stream
+ fp = fopen("/sd/bbhighscores.txt", "r"); //open file for brickbreak high scores
if(fp == NULL){
- printf("Error: Could not open file");
+ printf("Error: Could not open file"); //check successfully opened
} else {
int i = 0;
- rewind(fp);
+ rewind(fp); //return to start of file
- while(fscanf(fp, "%d,%f", &_index_array[i], &_array_of_values[i]) != EOF){
- i++;
+ while(fscanf(fp, "%d,%f", &_index_array[i], &_array_of_values[i]) != EOF){ //read into respective arrays while iterating through line by line
+ i++; //increment which line of array to write into
}
- fclose(fp);
+ fclose(fp); //close file stream
}
}
void BrickBreakerEngine::check_high_score(){
read_high_scores();
- for(int i = 4; i >= 0; i--){
- if(_array_of_values[i] < _score){
+ for(int i = 4; i >= 0; i--){ //quick algorithm to keep moving the current score
+ if(_array_of_values[i] < _score){ //up the leaderboard until it reaches a score greater than itself
_array_of_values[i+1] = _array_of_values[i];
- _array_of_values[i] = _score;
+ _array_of_values[i] = _score; //note: requires the file to be initialised with dummy scores in descending order
}
- }
+ } //produces updated array with the current score integrated into high scores if its a top 5 score
}
void BrickBreakerEngine::write_high_scores(){
check_high_score();
- FILE *fp;
- fp = fopen("/sd/bbhighscores.txt", "w");
+ FILE *fp; //open file stream
+ fp = fopen("/sd/bbhighscores.txt", "w"); //open brickbreaker high score file ready for writing
if(fp == NULL){
- printf("Error: Could not open file");
+ printf("Error: Could not open file"); //check open
} else {
- for(int i = 0; i < 5; i++){
- fprintf(fp, "%d, %f\n", _index_array[i], _array_of_values[i]);
+ for(int i = 0; i < 5; i++){
+ fprintf(fp, "%d, %f\n", _index_array[i], _array_of_values[i]); //send first 5 values of index and value array to SD card
}
- fclose(fp);
+ fclose(fp); //close file stream
}
}
void BrickBreakerEngine::time_warning(Gamepad &gamepad, int frame, int fps){
- gamepad.leds_on();
+ gamepad.leds_on(); //initially set all LEDs on
int game_length = 45 * fps;
- if(frame > 0.17 * game_length){
+ if(frame > 0.17 * game_length){ //when 1/6th of game played, turn first LED off
gamepad.led(6, 0);
}
- if(frame > 0.33 * game_length){
+ if(frame > 0.33 * game_length){ //when 1/3rd of game played, turn second LED off
gamepad.led(5, 0);
}
- if(frame > 0.5 * game_length){
+ if(frame > 0.5 * game_length){ //1/2 played, turn 3rd LED off
gamepad.led(4, 0);
}
- if(frame > 0.67 * game_length){
+ if(frame > 0.67 * game_length){ //2/3 played, turn 4th off
gamepad.led(3, 0);
}
- if(frame > 0.83 * game_length){
+ if(frame > 0.83 * game_length){ //5/6th played, turn 5th off
gamepad.led(2, 0);
}
- if(frame > 0.97 * game_length){
+ if(frame > 0.97 * game_length){ //turn final one off just before the game ends
gamepad.led(1, 0);
}
}
void BrickBreakerEngine::end(Gamepad &gamepad, N5110 &lcd){
- while(!(gamepad.check_event(gamepad.A_PRESSED))){
+ while(!(gamepad.check_event(gamepad.A_PRESSED))){ //check when user wants to advance
lcd.clear();
char buffer[2];
- sprintf(buffer, "%d", _score);
+ sprintf(buffer, "%d", _score); //read the final score into buffer
lcd.printString("Time up!", 18, 1);
- lcd.printString("You scored:", 9, 3);
- lcd.printString(buffer, 36, 4);
- lcd.printString("(A = back)", 24, 5);
+ lcd.printString("You scored:", 9, 3); //display time up message
+ lcd.printString(buffer, 36, 4); //display final score
+ lcd.printString("(A = back)", 24, 5); //check for advance message
lcd.refresh();
- wait(0.2);
+ wait(0.2); //longer duration between frames to reduce button bounce impact
}
}
\ No newline at end of file
--- a/BrickBreaker_Engine/BrickBreakerEngine.h Mon May 06 21:44:49 2019 +0000
+++ b/BrickBreaker_Engine/BrickBreakerEngine.h Thu May 09 01:09:18 2019 +0000
@@ -11,6 +11,51 @@
#include <cmath>
+/** BrickBreakerEngine Class
+@brief Library to power the BrickBreaker game mode
+@brief Includes feature to check for and write high scores
+
+@author James Cummins
+
+@code
+
+#include "mbed.h"
+#include "BrickBreakerEngine.h"
+#define RADIUS 3
+
+BrickBreakerEngine engine; //Constructor to create engine object
+AnalogIn randnoise(PTB0); //Get a random noise signal to seed the random square generator
+Gamepad gamepad;
+N5110 lcd(PTC9,PTC0,PTC7,PTD2,PTD1,PTC11);
+Ball ball;
+FXOS8700CQ accelerometer(I2C_SDA,I2C_SCL);
+
+int main(){
+ //Initialise the engine object with the ball's radius and the ball object
+ engine.init(RADIUS, ball)
+ int total_frames = 30000;
+ for (int i = 0; i < total_frames; i++){
+ //Not strictly needed as included in the initialiser
+ engine.set_score(0);
+ lcd.clear();
+ ball.read_input(accelerometer);
+ ball.update()
+
+ //Check for a collision between a square and the ball object
+ engine.check_square_collision(randnoise, ball); //increments score if there's a collision
+
+ engine.draw(lcd, ball);
+ lcd.refresh();
+
+ time_warning();
+ }
+ //End screen concludes game mode
+ engine.end(gamepad, lcd);
+ engine.write_high_scores; //only needs computing once so perform after while loop
+}
+@endcode
+*/
+
class BrickBreakerEngine {
public:
@@ -77,7 +122,7 @@
//private variables
int _index_array[6];
- float _array_of_values[6];
+ float _array_of_values[6]; //holds the 5 previous high scores and the score from previous play
int _ball_radius;
Vector2D _square_coord;
int _score;
--- a/Classic_Engine/ClassicEngine.cpp Mon May 06 21:44:49 2019 +0000
+++ b/Classic_Engine/ClassicEngine.cpp Thu May 09 01:09:18 2019 +0000
@@ -1,16 +1,19 @@
#include "ClassicEngine.h"
+//constructor
ClassicEngine::ClassicEngine(){
}
+//destructor
ClassicEngine::~ClassicEngine(){
}
+//initialiser
void ClassicEngine::init(Ball &ball, Map &map){
- _frames = 0;
- _ball_coord.x = 42;
+ _frames = 0; //set frames counted to 0
+ _ball_coord.x = 42; //set ball to middle of screen
_ball_coord.y = 24;
- _map_coord.x = 47;
+ _map_coord.x = 47; //set map to the start area
_map_coord.y = 25;
ball.set_position(_ball_coord);
map.set_map_display(_map_coord);
@@ -18,17 +21,17 @@
void ClassicEngine::classic_update(Ball &ball, FXOS8700CQ &accelerometer, Map &map){
map.read_input(accelerometer, ball);
- map.update();
- ball.set_position(_ball_coord);
- _frames++;
+ map.update(); //get map input from accelerometer and update region to display
+ ball.set_position(_ball_coord); //keep ball fixed to middle
+ _frames++; //increment frames count for timer
_map_coord = map.get_map_display();
- _abs_ball_pos.x = _ball_coord.x + _map_coord.x;
- _abs_ball_pos.y = _ball_coord.y + _map_coord.y;
+ _abs_ball_pos.x = _ball_coord.x + _map_coord.x; //update the ball's position in relation to the map
+ _abs_ball_pos.y = _ball_coord.y + _map_coord.y; //(even though it's fixed on the screen)
}
void ClassicEngine::classic_draw(N5110 &lcd, Map &map, Ball &ball){
- map.draw(lcd);
- ball.draw(lcd);
+ map.draw(lcd); //draw map
+ ball.draw(lcd); //draw ball
}
bool ClassicEngine::finished(){
@@ -41,83 +44,83 @@
}
else{ finished = false; }
printf("ball pos = %f , %f | finished = %d\n", _abs_ball_pos.x, _abs_ball_pos.y, finished);
- return finished;
+ return finished; //tell the game mode that the ball's reached the end of the course
}
void ClassicEngine::mode_complete(N5110 &lcd, Gamepad &gamepad, int fps){
float time_taken;
- while(!(gamepad.check_event(gamepad.A_PRESSED))){
- time_taken = _frames / fps;
+ while(!(gamepad.check_event(gamepad.A_PRESSED))){ //check for user advancing
+ time_taken = _frames / fps; //calculate time taken from no. of frames that passed
char buffer[6];
- sprintf(buffer, "%4.f", time_taken);
+ sprintf(buffer, "%4.f", time_taken); //write the time taken into a buffer
lcd.clear();
- lcd.printString("You win!", 18, 1);
+ lcd.printString("You win!", 18, 1); //win message
lcd.printString("Your time:", 12, 3);
- lcd.printString(buffer, 18,4);
+ lcd.printString(buffer, 18,4); //print the time taken
lcd.printChar('s',54,4);
lcd.printString("(A = back)", 24, 5);
lcd.refresh();
- wait(0.2);
+ wait(0.2); //slower frame rate to reduce button bounce effects
}
- write_high_scores(time_taken);
+ write_high_scores(time_taken); //check if high score, and update leaderboard if so
}
bool ClassicEngine::mode_failed(N5110 &lcd, Gamepad &gamepad, Ball &ball, Map &map){
- bool back_to_start_menu = false;
+ bool back_to_start_menu = false; //bool to store whether restarting or going to main menu
while(1){
wait(0.2);
lcd.clear();
- lcd.printString("Game over!", 12, 1);
+ lcd.printString("Game over!", 12, 1); //display potential options
lcd.printString("Back = A", 18, 3);
lcd.printString("Replay = B", 12, 4);
lcd.refresh();
if(gamepad.check_event(gamepad.A_PRESSED)){
- back_to_start_menu = true;
- break; }
+ back_to_start_menu = true; //return to start menu
+ break; } //use of break commands as while(!(a pressed || b pressed)) was buggy in run time
if(gamepad.check_event(gamepad.B_PRESSED)){
- back_to_start_menu = false;
+ back_to_start_menu = false; //restart
break; }
}
return back_to_start_menu;
}
void ClassicEngine::read_high_scores(){
- FILE *fp;
- fp = fopen("/sd/classichighscores.txt", "r");
+ FILE *fp; //open file stream
+ fp = fopen("/sd/classichighscores.txt", "r"); //open classic high scores file in read mode
if(fp == NULL){
- printf("Error: Could not open file");
+ printf("Error: Could not open file"); //check open
} else {
int i = 0;
- rewind(fp);
+ rewind(fp); //go back to start of file
- while(fscanf(fp, "%d,%f", &_index_array[i], &_array_of_values[i]) != EOF){
- i++;
+ while(fscanf(fp, "%d,%f", &_index_array[i], &_array_of_values[i]) != EOF){ //read into index and value arrays until end of file
+ i++; //increment which array row to read into
}
- fclose(fp);
+ fclose(fp); //close file stream
}
}
void ClassicEngine::check_high_score(int time_taken){
read_high_scores();
- for(int i = 4; i >= 0; i--){
- if(_array_of_values[i] > time_taken){
+ for(int i = 4; i >= 0; i--){ //algorithm to reorder high scores if new
+ if(_array_of_values[i] > time_taken){ //high score achieve or discard if not
_array_of_values[i+1] = _array_of_values[i];
- _array_of_values[i] = time_taken;
+ _array_of_values[i] = time_taken; //note: must seed high scores with ascending numbers when file made for first time
}
}
}
void ClassicEngine::write_high_scores(int time_taken){
check_high_score(time_taken);
- FILE *fp;
- fp = fopen("/sd/classichighscores.txt", "w");
+ FILE *fp; //open file stream
+ fp = fopen("/sd/classichighscores.txt", "w"); //open classic high score file in write mode
if(fp == NULL){
- printf("Error: Could not open file");
+ printf("Error: Could not open file"); //check open
} else {
for(int i = 0; i < 5; i++){
- fprintf(fp, "%d, %f\n", _index_array[i], _array_of_values[i]);
+ fprintf(fp, "%d, %f\n", _index_array[i], _array_of_values[i]); //write 5 highest values of high score array into file
}
- fclose(fp);
+ fclose(fp); //close file stream
}
}
--- a/Classic_Engine/ClassicEngine.h Mon May 06 21:44:49 2019 +0000
+++ b/Classic_Engine/ClassicEngine.h Thu May 09 01:09:18 2019 +0000
@@ -8,6 +8,56 @@
#include "Map.h"
#include "Pause.h"
+/** ClassicEngine Class
+@brief Library to power the Classic game mode
+@brief Includes feature to check for and update high scores
+
+@author James Cummins
+
+@code
+
+#include "mbed.h"
+#include "ClassicEngine.h"
+
+ClassicEngine engine;
+Ball ball;
+Map map;
+N5110 lcd(PTC9,PTC0,PTC7,PTD2,PTD1,PTC11);
+FXOS8700CQ accelerometer(I2C_SDA,I2C_SCL);
+Gamepad gamepad;
+
+int main(){
+ int fps = 30; //set the game mode frames per sec
+ classic.init(ball, map); //initialise the engine before use
+ bool collision = false; //create bool to check whether to continue
+ while(!(collision)){
+
+ //classic update contains methods for reading and updating map and ball
+ classic.classic_update(ball, accelerometer, map);
+ //use clear, classic draw and refresh together to re-render the screen each frame
+ lcd.clear();
+ classic.classic_draw(lcd, map, ball);
+ lcd.refresh();
+ wait(1/fps);
+ //Check for successful completion of game and display appropriate message
+ if(classic.finished()){ //check if the game has been completed
+ //mode_complete includes feature to update high scores
+ classic.mode_complete(lcd, gamepad, fps);
+ break;
+ }
+ //Check for game failure and display appropriate message with option to
+ //restart or go back
+ if(map.check_wall_collision(gamepad, ball)){ //end the game if collision with wall
+ collision = classic.mode_failed(lcd, gamepad, ball, map); //gives the option to restart the game (and stay in while loop) or quit
+ //reset the game mode to the beginning if user wants to play again
+ if(!(collision)){ classic.init(ball, map); }
+ }
+ }
+}
+@endcode
+*/
+
+
class ClassicEngine {
public:
--- a/Map/Map.cpp Mon May 06 21:44:49 2019 +0000
+++ b/Map/Map.cpp Thu May 09 01:09:18 2019 +0000
@@ -7,19 +7,19 @@
}
void Map::init(){
- _coord.x = 47;
+ _coord.x = 47; //initialise the map region to the start area
_coord.y = 25;
}
void Map::read_input(FXOS8700CQ &accelerometer, Ball &ball){
Data values = accelerometer.get_values();
- int ball_speed = ball.get_ball_speed();
- _map_change.x = -(1+0.5*ball_speed)*values.ay;
+ int ball_speed = ball.get_ball_speed(); //get the sensitivity from ball object
+ _map_change.x = -(1+0.5*ball_speed)*values.ay; //axes of accelerometer different to gamepad so use -y for x and vice versa
_map_change.y = -(1+0.5*ball_speed)*values.ax;
}
void Map::update(){
- _coord.x += _map_change.x;
+ _coord.x += _map_change.x; //map change is the equivalent of velocity in ball.cpp
_coord.y += _map_change.y;
if(_coord.x < 0){ _coord.x = 0;} //boundary conditions to stop the
if(_coord.y < 0){ _coord.y = 0;} //the programme trying to display
@@ -29,54 +29,56 @@
void Map::draw(N5110 &lcd){
bool pixelstate = false;
- for(int y = _coord.y; y < (48+_coord.y); y++){
- for(int x = _coord.x; x < (84+_coord.x); x++){
- if(gamemap[y][x] == 1){ pixelstate = true;}
- else{ pixelstate = false;}
- lcd.setPixel((x-_coord.x), (y-_coord.y), pixelstate);
+ for(int y = _coord.y; y < (48+_coord.y); y++){ //row by row
+ for(int x = _coord.x; x < (84+_coord.x); x++){ //get each pixel from the
+ if(gamemap[y][x] == 1){ pixelstate = true;} //gamemap array
+ else{ pixelstate = false;} //and set the pixel according to its value in gamemap array
+ lcd.setPixel((x-_coord.x), (y-_coord.y), pixelstate); //easier to use than draw sprite with only part of a very large sprite
}
}
}
Vector2D Map::get_map_display(){
- Vector2D top_left_coord = _coord;
+ Vector2D top_left_coord = _coord; //top left coord used to represent entire screen region
return top_left_coord;
}
void Map::set_map_display(Vector2D coord){
- _coord = coord;
+ _coord = coord; //change private member variable
}
bool Map::check_wall_collision(Gamepad &gamepad, Ball &ball){
bool collision = false;
- /*Vector2D ball_screen_pos = ball.get_position();
+ Vector2D ball_screen_pos = ball.get_position();
Vector2D c;
- c.x = ball_screen_pos.x + _coord.x;
- c.y = ball_screen_pos.y + _coord.y;
+ c.x = ball_screen_pos.x + _coord.x; //c represents the absolute position of the ball's centre
+ c.y = ball_screen_pos.y + _coord.y; //relative to the game map
Vector2D ball_pixels[37] = {
- {c.x,c.y},{c.x+1,c.y},{c.x+2,c.y},{c.x+3,c.y},{c.x-1,c.y},{c.x-2,c.y},
+ {c.x,c.y},{c.x+1,c.y},{c.x+2,c.y},{c.x+3,c.y},{c.x-1,c.y},{c.x-2,c.y}, //this is every pixel in ball
{c.x-3,c.y},{c.x,c.y+1},{c.x+1,c.y+1},{c.x+2,c.y+1},{c.x+3,c.y+1},
- {c.x-1,c.y+1},{c.x-2,c.y+1},{c.x-3,c.y+1},{c.x,c.y-1},{c.x+1,c.y-1},
- {c.x+2,c.y-1},{c.x+3,c.y-1},{c.x-1,c.y-1},{c.x-2,c.y-1},{c.x-3,c.y-1},
- {c.x,c.y+2},{c.x+1,c.y+2},{c.x+2,c.y+2},{c.x-1,c.y+2},{c.x-2,c.y+2},
+ {c.x-1,c.y+1},{c.x-2,c.y+1},{c.x-3,c.y+1},{c.x,c.y-1},{c.x+1,c.y-1}, //could this be done with
+ {c.x+2,c.y-1},{c.x+3,c.y-1},{c.x-1,c.y-1},{c.x-2,c.y-1},{c.x-3,c.y-1}, //same algorithm as for
+ {c.x,c.y+2},{c.x+1,c.y+2},{c.x+2,c.y+2},{c.x-1,c.y+2},{c.x-2,c.y+2}, //lcd.drawCircle?
{c.x,c.y-2},{c.x+1,c.y-2},{c.x+2,c.y-2},{c.x-1,c.y-2},{c.x-2,c.y-2},
- {c.x,c.y+3},{c.x+1,c.y+3},{c.x-1,c.y+3},{c.x,c.y-3},{c.x+1,c.y-3},
+ {c.x,c.y+3},{c.x+1,c.y+3},{c.x-1,c.y+3},{c.x,c.y-3},{c.x+1,c.y-3}, //this is fixed for a radius of 3
{c.x-1,c.y-3} };
for(int i = 0; i < 37; i++){
int y = ball_pixels[i].y;
int x = ball_pixels[i].x;
- if(gamemap[y][x] == 1){
+ if(gamemap[y][x] == 1){ //check each pixel in the ball to see if it is on a '1' in game map (representing wall)
collision = true;
printf("colliding pixel = %d,%d\n", x, y);
- break;
- } else { collision = false; }
- }*/
+ break; //break with true if wall collision
+ } else { collision = false; } //keep iterating if not
+ }
return collision;
}
bool Map::get_coordinate(Vector2D coord){
bool position;
- if(gamemap[coord.y][coord.x] == 1){ position == true; }
- else{ position == false; }
+ int x = coord.x;
+ int y = coord.y;
+ if(gamemap[y][x] == 1){ position == true; } //find the desired coord in the game map
+ else{ position == false; } //return true if its a wall, false if it's pathway
return position;
}
\ No newline at end of file
--- a/Map/Map.h Mon May 06 21:44:49 2019 +0000
+++ b/Map/Map.h Thu May 09 01:09:18 2019 +0000
@@ -7,6 +7,60 @@
#include "Gamepad.h"
#include "Ball.h"
+/** Map Class
+@brief Library for interacting with the Classic game mode Map
+
+@author James Cummins
+
+@code
+
+#include "mbed.h"
+#include "Map.h"
+
+//Create a map object
+Map map;
+Ball ball;
+Gamepad gamepad;
+FXOS8700CQ accelerometer(I2C_SDA, I2C_SCL);
+N5110 lcd(PTC9,PTC0,PTC7,PTD2,PTD1,PTC11);
+
+int main(){
+ //Initialise the map first
+ map.init();
+
+ //Use check wall collision to decide whether to continue game or not
+ while(!(map.check_wall_collision())){
+
+ //read input and update methods check the user input and update
+ //the map region to be displayed accordingly
+ map.read_input(accelerometer, ball);
+ map.update();
+
+ //get and set map display can be used to check the intended region of the
+ //map to print and correct it if it's out of bounds
+ Vector2D map_region = map.get_map_display();
+ if(map_region.x > 500){
+ map_region.x = 500;
+ map.set_map_display(map_region);
+ }
+
+ //combine clear, draw and refresh to update LCD screen each frame
+ lcd.clear();
+ map.draw(lcd);
+ lcd.refresh();
+
+ //Use get coordinate to check if an object (e.g. ball) is centred
+ //on a shaded part of the game map
+ Vector2D coord = ball.get_position();
+ int pixel = map.get_coordinate(coord);
+ if(pixel == 1){ break; }
+ }
+}
+
+@endcode
+
+*/
+
class Map {
public:
@@ -62,6 +116,7 @@
* @returns
* true - coordinate contains a '1'
* false - coordinate contains a '0'
+ * @details Method included for testing purposes rather than use in game code
*/
bool get_coordinate(Vector2D coord);
--- a/Options_Engine/OptionsEngine.cpp Mon May 06 21:44:49 2019 +0000
+++ b/Options_Engine/OptionsEngine.cpp Thu May 09 01:09:18 2019 +0000
@@ -1,94 +1,97 @@
#include "OptionsEngine.h"
+//constructor
OptionsEngine::OptionsEngine(){
}
+//destructor
OptionsEngine::~OptionsEngine(){
}
+//initialiser
void OptionsEngine::init(){
- _state = BRIGHTNESS;
- _brightness = 0.5;
- _ball_speed = 5;
+ _state = BRIGHTNESS; //first item in menu
+ _brightness = 0.5; //medium brightness
+ _ball_speed = 5; // 5/10 sensitivity
}
void OptionsEngine::display_options(N5110 &lcd){
- lcd.printString("Options menu", 6, 0);
+ lcd.printString("Options menu", 6, 0); //text for each line of display
lcd.printString("Brightness", 12, 2);
lcd.printString("Ball speed", 12, 3);
lcd.printString("High scores", 9, 4);
}
Option OptionsEngine::option_selection(Gamepad &gamepad, N5110 &lcd){
- OptionSelection fsm[3] = {
- {2,{HIGH_SCORES, BALL_SPEED, BRIGHTNESS}},
- {3,{BRIGHTNESS, HIGH_SCORES, BALL_SPEED}},
- {4,{BALL_SPEED, BRIGHTNESS, HIGH_SCORES}}
- };
- if(gamepad.get_direction() == N){ _next_state = 0; }
- else if(gamepad.get_direction() == S){ _next_state = 1; }
- else{ _next_state = 2; }
- _state = fsm[_state].next_state[_next_state];
+ OptionSelection fsm[3] = { //finite state machine to power the menu
+ {2,{HIGH_SCORES, BALL_SPEED, BRIGHTNESS}}, //output (e.g. 2,3,4) is line to print arrows on for user interface
+ {3,{BRIGHTNESS, HIGH_SCORES, BALL_SPEED}}, //next_state[0] is the option above current one
+ {4,{BALL_SPEED, BRIGHTNESS, HIGH_SCORES}} //next_state[1] is the option below current one
+ }; //next_state[2] is current state
+ if(gamepad.get_direction() == N){ _next_state = 0; } //move arrows up
+ else if(gamepad.get_direction() == S){ _next_state = 1; } //move arrows down
+ else{ _next_state = 2; } //keep arrows the same (default)
+ _state = fsm[_state].next_state[_next_state]; //calculate next state
lcd.printChar('>', 0, fsm[_state].output);
- lcd.printChar('<', 78, fsm[_state].output);
+ lcd.printChar('<', 78, fsm[_state].output); //draw arrows
return _state;
}
void OptionsEngine::change_brightness(Gamepad &gamepad, N5110 &lcd){
- while(!(gamepad.check_event(gamepad.A_PRESSED))){
+ while(!(gamepad.check_event(gamepad.A_PRESSED))){ //check for user selection
lcd.clear();
- lcd.printString("Brightness", 12, 0);
+ lcd.printString("Brightness", 12, 0); //text to display on each line
lcd.printString("Use L and R to", 0, 3);
lcd.printString("change", 24, 4);
lcd.printString("A = confirm", 9, 5);
- lcd.drawRect(10, 12, 63, 8, FILL_TRANSPARENT);
+ lcd.drawRect(10, 12, 63, 8, FILL_TRANSPARENT); //outside of slider to display the brightness controller
read_brightness_input(gamepad);
for(int i = 0; i < _brightness*10; i ++){
- lcd.drawRect(12+6*i, 14, 5, 4, FILL_BLACK);
+ lcd.drawRect(12+6*i, 14, 5, 4, FILL_BLACK); //draw small rectangles to represent the current brightness
}
- lcd.setBrightness(_brightness);
+ lcd.setBrightness(_brightness); //set brightness with N5110 class
lcd.refresh();
- wait(0.2);
+ wait(0.2); //avoid button bounce with large time between frames
}
}
void OptionsEngine::read_brightness_input(Gamepad &gamepad){
if(gamepad.check_event(gamepad.L_PRESSED)){ _brightness -= 0.1f; } //Use of f to explicitly convert to a float (to fit declaration type in header file).
if(gamepad.check_event(gamepad.R_PRESSED)){ _brightness += 0.1f; } //Otherwise 0.1 is implicitly converted to a double (giving warning messages).
- if(_brightness < 0){ _brightness = 0; }
+ if(_brightness < 0){ _brightness = 0; } //keep within range of 0 - 1
if(_brightness > 1){ _brightness = 1; }
/*printf("Brightness = %f\n", _brightness);*/
}
void OptionsEngine::change_ball_speed(Gamepad &gamepad, N5110 &lcd, Ball &ball){
- while(!(gamepad.check_event(gamepad.A_PRESSED))){
+ while(!(gamepad.check_event(gamepad.A_PRESSED))){ //check for user selection
lcd.clear();
- lcd.printString("Ball Speed", 12, 0);
+ lcd.printString("Ball Speed", 12, 0); //text for each line of display
lcd.printString("Use L and R to", 0, 3);
lcd.printString("change", 24, 4);
lcd.printString("A = confirm", 9, 5);
lcd.drawRect(10, 12, 63, 8, FILL_TRANSPARENT);
- read_ball_speed_input(gamepad);
+ read_ball_speed_input(gamepad); //get values for sensitivity/ball speed
for(int i = 0; i < _ball_speed; i ++){
- lcd.drawRect(12+6*i, 14, 5, 4, FILL_BLACK);
+ lcd.drawRect(12+6*i, 14, 5, 4, FILL_BLACK); //draw small rectangles in the same manner as brightness control
}
ball.set_ball_speed(_ball_speed);
lcd.refresh();
- wait(0.2);
+ wait(0.2); //avoid button bounce
}
}
void OptionsEngine::read_ball_speed_input(Gamepad &gamepad){
- if(gamepad.check_event(gamepad.L_PRESSED)){ _ball_speed -= 1; }
+ if(gamepad.check_event(gamepad.L_PRESSED)){ _ball_speed -= 1; } //increment on R press, decrement on L press
if(gamepad.check_event(gamepad.R_PRESSED)){ _ball_speed += 1; }
- if(_ball_speed < 0){ _ball_speed = 0; }
+ if(_ball_speed < 0){ _ball_speed = 0; } //keep within range 0 - 10
if(_ball_speed > 10){ _ball_speed = 10; }
}
void OptionsEngine::view_high_scores(Gamepad &gamepad, N5110 &lcd){
- _leaderboard = CLASSIC_MODE;
- while(!(gamepad.check_event(gamepad.A_PRESSED))){
- if(gamepad.check_event(gamepad.R_PRESSED)){ _leaderboard = BRICKBREAKER_MODE; }
+ _leaderboard = CLASSIC_MODE; //initialise to look at classic leaderboard first
+ while(!(gamepad.check_event(gamepad.A_PRESSED))){ //check for user selection
+ if(gamepad.check_event(gamepad.R_PRESSED)){ _leaderboard = BRICKBREAKER_MODE; } //use L and R to flick between the two leaderboards
if(gamepad.check_event(gamepad.L_PRESSED)){ _leaderboard = CLASSIC_MODE; }
lcd.clear();
print_high_scores(lcd);
@@ -98,58 +101,58 @@
}
void OptionsEngine::read_classic_high_scores(){
- FILE *fp;
- fp = fopen("/sd/classichighscores.txt", "r");
+ FILE *fp; //open file stream
+ fp = fopen("/sd/classichighscores.txt", "r"); //classic high scores file in read mode
if(fp == NULL){
- printf("Error: Could not open file");
+ printf("Error: Could not open file"); //check open
} else {
int i = 0;
- rewind(fp);
+ rewind(fp); //reset to start of file to start reading
- while(fscanf(fp, "%d,%f", &_classic_index[i], &_classic_values[i]) != EOF){
- i++;
+ while(fscanf(fp, "%d,%f", &_classic_index[i], &_classic_values[i]) != EOF){ //read each index and value into arrays till end of file
+ i++; //increment counter
}
- fclose(fp);
+ fclose(fp); //close file stream
}
}
void OptionsEngine::read_bb_high_scores(){
- FILE *fp;
- fp = fopen("/sd/bbhighscores.txt", "r");
+ FILE *fp; //open file stream
+ fp = fopen("/sd/bbhighscores.txt", "r"); //brickbreaker high scores in read mode
if(fp == NULL){
- printf("Error: Could not open file");
+ printf("Error: Could not open file"); //check open
} else {
int i = 0;
- rewind(fp);
+ rewind(fp); //reset to start of file
- while(fscanf(fp, "%d,%f", &_bb_index[i], &_bb_values[i]) != EOF){
- i++;
+ while(fscanf(fp, "%d,%f", &_bb_index[i], &_bb_values[i]) != EOF){ //read each index and value into array till end of file
+ i++; //increment counter
}
- fclose(fp);
+ fclose(fp); //close file stream
}
}
void OptionsEngine::print_high_scores(N5110 &lcd){
- if(_leaderboard == CLASSIC_MODE){
+ if(_leaderboard == CLASSIC_MODE){ //check which leaderboard to display
read_classic_high_scores();
- lcd.printString("Classic", 21, 0);
+ lcd.printString("Classic", 21, 0); //text for user interface with leaderboard
lcd.printString("R>", 72, 3);
char buffer[14];
- for(int i = 0; i < 5; i++){
- sprintf(buffer, "%d. %.0fs", _classic_index[i], _classic_values[i]);
- lcd.printString(buffer, 0, i + 1);
+ for(int i = 0; i < 5; i++){ //iterate for each of 5 high scores
+ sprintf(buffer, "%d. %.0fs", _classic_index[i], _classic_values[i]); //update the buffer for each line of high scores
+ lcd.printString(buffer, 0, i + 1); //print the respective high score to screen
}
}
- if(_leaderboard == BRICKBREAKER_MODE){
+ if(_leaderboard == BRICKBREAKER_MODE){ //check which leaderboard to display
read_bb_high_scores();
- lcd.printString("Brickbreak", 12, 0);
+ lcd.printString("Brickbreak", 12, 0); //text for user interface
lcd.printString("<L", 72, 3);
char buffer[14];
- for(int i = 0; i < 5; i++){
- sprintf(buffer, "%d. %.0f", _bb_index[i], _bb_values[i]);
- lcd.printString(buffer, 0, i + 1);
+ for(int i = 0; i < 5; i++){ //iterate for each of 5 high scores
+ sprintf(buffer, "%d. %.0f", _bb_index[i], _bb_values[i]); //update buffer for each line of high scores
+ lcd.printString(buffer, 0, i + 1); //print respective high score to screen
}
}
}
\ No newline at end of file
--- a/Options_Engine/OptionsEngine.h Mon May 06 21:44:49 2019 +0000
+++ b/Options_Engine/OptionsEngine.h Thu May 09 01:09:18 2019 +0000
@@ -21,6 +21,46 @@
Option next_state[3]; /**< Array of enums for possible next option */
};
+/** Options Engine Class
+@brief Library to power the options menu
+@brief Features methods
+
+@author James Cummins
+
+@code
+
+#include "mbed.h"
+#include "OptionsEngine.h"
+
+//Create an engine object for the Options Menu
+OptionsEngine opt;
+Gamepad gamepad;
+N5110 lcd(PTC9,PTC0,PTC7,PTD2,PTD1,PTC11);
+Ball ball;
+
+int main(){
+ //Enum for the user's option choice initialised to first menu item (brightness)
+ Option choice = BRIGHTNESS;
+ while(!(gamepad.check_event(gamepad.A_PRESSED))){
+ //display options renders the options menu
+ //option selection renders the arrows which point to the current selection
+ lcd.clear();
+ opt.display_options(lcd);
+ choice = opt.option_selection(gamepad, lcd);
+ lcd.refresh();
+ //longer wait time than normal game fps to compensate for button bounce
+ wait(0.2);
+ }
+ //each menu option called by its respective enum
+ if(choice == BRIGHTNESS){ opt.change_brightness(gamepad, lcd); }
+ if(choice == BALL_SPEED){ opt.change_ball_speed(gamepad, lcd, ball); }
+ if(choice == HIGH_SCORES){ opt.view_high_scores(gamepad, lcd); }
+}
+
+@endcode
+
+*/
+
class OptionsEngine {
public:
--- a/Pause/Pause.cpp Mon May 06 21:44:49 2019 +0000
+++ b/Pause/Pause.cpp Thu May 09 01:09:18 2019 +0000
@@ -1,23 +1,26 @@
#include "Pause.h"
+//constructor
Pause::Pause(){
}
+//destructor
Pause::~Pause(){
}
+////initialiser
void Pause::init(){
- _state = RESUME;
+ _state = RESUME; //set arrows to point to first item in the menu
}
PauseOption Pause::pause_menu(Gamepad &gamepad, N5110 &lcd, int fps){
- PauseOption choice = RESUME;
- while(!(gamepad.check_event(gamepad.A_PRESSED))){
+ PauseOption choice = RESUME; //choice stores the state to be selected and pointed to with arrows
+ while(!(gamepad.check_event(gamepad.A_PRESSED))){ //check for user selection
lcd.clear();
- display_pause_options(lcd);
- choice = pause_selection(gamepad, lcd);
+ display_pause_options(lcd); //render the menu on the screen
+ choice = pause_selection(gamepad, lcd); //update currently selected choice and point to it with arrows
lcd.refresh();
- wait(0.2);
+ wait(0.2); //avoid button bounce as much as poss
}
return choice;
}
@@ -26,16 +29,16 @@
int Pause::brickbreaker_action(PauseOption choice, Gamepad &gamepad, N5110 &lcd, int frame, int fps){
int jump_to_frame = frame;
- if(choice == RESUME){ jump_to_frame = frame; } //Just keep code iterating
- if(choice == RESTART){ jump_to_frame = 0; } //return to frame 1 if restarted
- if(choice == QUIT){ jump_to_frame = 45*fps; } //jump to final frame
- if(choice == HELP){ brickbreaker_help(gamepad, lcd); }
- return jump_to_frame; //display relevant help screen
+ if(choice == RESUME){ jump_to_frame = frame; } //Just keep code iterating
+ if(choice == RESTART){ jump_to_frame = 0; } //return to frame 1 if restarted
+ if(choice == QUIT){ jump_to_frame = 45*fps; } //jump to final frame
+ if(choice == HELP){ brickbreaker_help(gamepad, lcd); } //display relevant help screen
+ return jump_to_frame;
}
void Pause::display_pause_options(N5110 &lcd){
- lcd.printString("GAME PAUSED:", 6, 0);
+ lcd.printString("GAME PAUSED:", 6, 0); //text for each line of the display
lcd.printString("Resume", 24, 1);
lcd.printString("Restart", 21, 2);
lcd.printString("Quit", 30, 3);
@@ -44,26 +47,26 @@
}
PauseOption Pause::pause_selection(Gamepad &gamepad, N5110 &lcd){
- PauseSelection fsm[4] = {
- {1,{HELP,RESTART,RESUME}},
- {2,{RESUME,QUIT,RESTART}},
- {3,{RESTART,HELP,QUIT}},
- {4,{QUIT,RESUME,HELP}}
+ PauseSelection fsm[4] = { //state machine to power the pause menu
+ {1,{HELP,RESTART,RESUME}}, //output (1,2,3 or 4) is the line to print the arrows on
+ {2,{RESUME,QUIT,RESTART}}, //next_state[0] is the option above the current item
+ {3,{RESTART,HELP,QUIT}}, //next_state[1] is the option below the current item
+ {4,{QUIT,RESUME,HELP}} //next_state[2] is the current item/state
};
- if(gamepad.get_direction() == N){ _next_state = 0;}
- else if(gamepad.get_direction() == S){ _next_state = 1;}
- else{ _next_state = 2;}
- _state = fsm[_state].next_state[_next_state];
- lcd.printString(">", 6, fsm[_state].output);
+ if(gamepad.get_direction() == N){ _next_state = 0;} //move up
+ else if(gamepad.get_direction() == S){ _next_state = 1;} //move down
+ else{ _next_state = 2;} //arrows in same position (default)
+ _state = fsm[_state].next_state[_next_state]; //update state
+ lcd.printString(">", 6, fsm[_state].output); //print arrows to LCD display
lcd.printString("<", 72, fsm[_state].output);
return _state;
}
void Pause::classic_help(Gamepad &gamepad, N5110 &lcd){
- while(!(gamepad.check_event(gamepad.A_PRESSED))){
+ while(!(gamepad.check_event(gamepad.A_PRESSED))){ //check for user advancing
lcd.clear();
- lcd.printString("Help", 30, 0);
- lcd.printString("Don't leave", 0, 1);
+ lcd.printString("Help", 30, 0); //display each line of help
+ lcd.printString("Don't leave", 0, 1); //on LCD display
lcd.printString("the path! Tilt", 0, 2);
lcd.printString("pad to roll", 0, 3);
lcd.printString("the ball", 0, 4);
@@ -74,10 +77,10 @@
}
void Pause::brickbreaker_help(Gamepad &gamepad, N5110 &lcd){
- while(!(gamepad.check_event(gamepad.A_PRESSED))){
+ while(!(gamepad.check_event(gamepad.A_PRESSED))){ //check for user advancing
lcd.clear();
- lcd.printString("Help", 30, 0);
- lcd.printString("Tilt gamepad", 0, 1);
+ lcd.printString("Help", 30, 0); //display each line of help
+ lcd.printString("Tilt gamepad", 0, 1); //on LCD display
lcd.printString("to move ball", 0, 2);
lcd.printString("Game length=", 0, 3);
lcd.printString("45 secs", 0, 4);
--- a/Pause/Pause.h Mon May 06 21:44:49 2019 +0000
+++ b/Pause/Pause.h Thu May 09 01:09:18 2019 +0000
@@ -26,6 +26,52 @@
PauseOption next_state[3]; /**<Array of enums for possible next option*/
};
+/** Pause Class
+@brief Library to power the pause menu
+@brief Can pass frame values to control the flow of the game modes they're
+@brief utilised in, enabling features like restarting and quitting
+
+@author James Cummins
+
+@code
+
+#include "mbed.h"
+#include "Pause.h"
+
+Pause pause; //create a pause object for the pause menu
+Gamepad gamepad;
+N5110 lcd(PTC9,PTC0,PTC7,PTD2,PTD1,PTC11);
+
+int main(){
+ //first initialise the pause menu so it points to top item first
+ pause.init();
+ int game_length = 90; //desired game mode length in seconds
+ int fps = 30; //frames per sec of the game mode
+
+ //use either one or the other of these (for the correct game mode)
+ //to display instructions before the game commences
+ pause.brickbreaker_help(gamepad, lcd);
+ pause.classic_help(gamepad, lcd);
+
+ for(int i = 0; i < game_length*fps; i++){
+ //
+ //
+ //code to operate a time based game mode
+ //
+ //
+
+ if(gamepad.check_event(gamepad.BACK_PRESSED)){
+ //retrieve the user's choice from the pause menu
+ PauseOption choice = pause.pause_menu(gamepad, lcd, fps);
+ //jump to the appropriate point in the game mode
+ i = pause.brickbreaker_action(choice, gamepad, lcd, i, fps);
+ }
+ }
+}
+
+@endcode
+*/
+
class Pause {
public:
--- a/main.cpp Mon May 06 21:44:49 2019 +0000
+++ b/main.cpp Thu May 09 01:09:18 2019 +0000
@@ -59,13 +59,13 @@
int fps = 16; //declared globally so it doesn't have to be passed to
//the different game mode functions
int main(){
- init();
- startscreen();
- while(1){
- StartOption choice_selected = menu();
- if(choice_selected == CLASSIC){ classic_mode();}
- if(choice_selected == BRICKBREAKER){ brickbreaker_mode();}
- if(choice_selected == OPTIONS){ options_menu();}
+ init(); //first initialise all objects
+ startscreen(); //then display the introductory screen
+ while(1){ //keep game running until power is removed
+ StartOption choice_selected = menu(); //get which mode user wants from the start menu
+ if(choice_selected == CLASSIC){ classic_mode();} //jump to a game mode once
+ if(choice_selected == BRICKBREAKER){ brickbreaker_mode();} //its respective enum is received
+ if(choice_selected == OPTIONS){ options_menu();} //from the start menu
}
}
@@ -73,10 +73,10 @@
//////////////Start up functions///////////////////
-void init(){
+void init(){ //initialise all objects in the game
gamepad.init();
- lcd.init();
- lcd.setContrast(0.55);
+ lcd.init(); //some objects are initialised again elsewhere
+ lcd.setContrast(0.55); //e.g. to reset a game mode when restart is pressed
classic.init(ball, map);
brick.init(RADIUS, ball);
opt.init();
@@ -89,25 +89,25 @@
void startscreen() {
lcd.clear();
- char gamename[] = {'L', 'A', 'B', 'Y', 'R', 'I', 'N', 'T', 'H', ' ', ' ', '\0'};
+ char gamename[] = {'L', 'A', 'B', 'Y', 'R', 'I', 'N', 'T', 'H', ' ', ' ', '\0'}; //char array containing the game title
int i = 0;
- for(int a = 0; a < 35; a++){
+ for(int a = 0; a < 35; a++){ //from first letter position to end of the screen at 2 pixel intervals
lcd.clear();
- lcd.drawCircle(24+2*a, 21, 3, FILL_BLACK);
+ lcd.drawCircle(24+2*a, 21, 3, FILL_BLACK); //move the ball 2 pixels at a time
for (i = 0; i < a/3; i++) {
- lcd.printChar(gamename[i], 15+i*6, 2);
- lcd.refresh();
+ lcd.printChar(gamename[i], 15+i*6, 2); //print the next letter in game title once the ball has moved past
+ lcd.refresh(); //display all contents on LCD display
}
wait_ms(50);
}
- lcd.printString("Press start", 9, 4);
+ lcd.printString("Press start", 9, 4); //instruct user how to advance
lcd.printString("to play >", 15, 5);
- lcd.refresh();
+ lcd.refresh();
bool advance = false;
- while (!advance){
+ while (!advance){ //check for user advancing
if (gamepad.check_event(gamepad.START_PRESSED)){
- lcd.clear();
- lcd.refresh();
+ lcd.clear(); //if user presses start, clear screen
+ lcd.refresh(); //before advancing to start menu
advance = true;
}
else { advance = false; }
@@ -115,26 +115,26 @@
}
StartOption menu(){
- StartSelection fsm[3] = {
- {0,{OPTIONS,BRICKBREAKER,CLASSIC}},
- {2,{CLASSIC,OPTIONS,BRICKBREAKER}},
- {4,{BRICKBREAKER,CLASSIC,OPTIONS}}
+ StartSelection fsm[3] = { //state machine to power start menu
+ {0,{OPTIONS,BRICKBREAKER,CLASSIC}}, //next_state[0] always holds the option above the current one
+ {2,{CLASSIC,OPTIONS,BRICKBREAKER}}, //next_state[1] always holds the option below the current one
+ {4,{BRICKBREAKER,CLASSIC,OPTIONS}} //next_state[2] always holds the current option
};
StartOption state = CLASSIC; //start with the arrow on the top option
int next = 2; //next_state = 2 so that by default it doesn't change arrow position
- while(!(gamepad.check_event(gamepad.A_PRESSED))){ //select choice by pushing joystick to the right
+ while(!(gamepad.check_event(gamepad.A_PRESSED))){ //select choice with A
state = fsm[state].next_state[next];
lcd.clear();
- if(gamepad.get_direction() == N){ next = 0;}
- else if(gamepad.get_direction() == S){ next = 1;}
- else {next = 2;}
- print_start_menu(fsm[state].output);
+ if(gamepad.get_direction() == N){ next = 0;} //move arrow up
+ else if(gamepad.get_direction() == S){ next = 1;} //move arrow down
+ else {next = 2;} //keep arrow in same position
+ print_start_menu(fsm[state].output); //print on LCD display
lcd.refresh();
- wait(0.25);
+ wait(0.25); //longer wait than 1/fps to reduce the impact of button bounce
}
lcd.clear();
- lcd.refresh();
- return state;
+ lcd.refresh(); //clear display before moving on to a game mode
+ return state; //tell main which game mode to run
}
void print_start_menu(int output){
@@ -149,23 +149,23 @@
void classic_mode(){
classic.init(ball, map);
- pause.classic_help(gamepad, lcd);
- bool collision = false;
+ pause.classic_help(gamepad, lcd); //display how to play instructions before start of game
+ bool collision = false; //used to determine whether to keep iterating or not
while(!(collision)){
- classic.classic_update(ball, accelerometer, map);
- lcd.clear();
+ classic.classic_update(ball, accelerometer, map); //methods to update the game
+ lcd.clear(); //and render it as the user plays
classic.classic_draw(lcd, map, ball);
lcd.refresh();
wait(1/fps);
- if(gamepad.check_event(gamepad.BACK_PRESSED)){ //pause menu
- PauseOption choice = pause.pause_menu(gamepad, lcd, fps);
- if(choice == RESUME){} //the different options must be processed
- if(choice == RESTART){ classic.init(ball, map); } //in main.cpp as they have different
- if(choice == QUIT){ break; } //return types so can't be passed into main
- if(choice == HELP){ pause.classic_help(gamepad, lcd); }
+ if(gamepad.check_event(gamepad.BACK_PRESSED)){ //check for use of the pause menu
+ PauseOption choice = pause.pause_menu(gamepad, lcd, fps); //retrieve user's input
+ if(choice == RESUME){} //the different options must be processed
+ if(choice == RESTART){ classic.init(ball, map); } //in main.cpp as they have different
+ if(choice == QUIT){ break; } //return types so can't be passed into main
+ if(choice == HELP){ pause.classic_help(gamepad, lcd); } //by one public method in pause.h
}
if(classic.finished()){ //check if the game has been completed
- classic.mode_complete(lcd, gamepad, fps);
+ classic.mode_complete(lcd, gamepad, fps); //display time taken and break from game mode
break;
}
if(map.check_wall_collision(gamepad, ball)){ //end the game if collision with wall
@@ -176,10 +176,10 @@
}
void brickbreaker_mode(){
- pause.brickbreaker_help(gamepad, lcd);
+ pause.brickbreaker_help(gamepad, lcd); //display instructions before start of game
for(int i = 0; i < 45*fps; i++){
if(i == 1){ brick.set_score(0); } //reset score when game restarts
- ball.read_input(accelerometer);
+ ball.read_input(accelerometer); //methods to continue updating and rendering the game
ball.update();
/*Vector2D position = _ball.get_position();
printf("ball_x = %f | ball_y = %f\n", position.x, position.y); //note: running with tests causes the game to run slow and take ~2min30s*/
@@ -188,28 +188,28 @@
brick.brickbreaker_draw(lcd, ball);
lcd.refresh();
wait_ms(1000/fps);
- if(gamepad.check_event(gamepad.BACK_PRESSED)){
- PauseOption choice = pause.pause_menu(gamepad, lcd, fps);
- i = pause.brickbreaker_action(choice, gamepad, lcd, i, fps); //returns which frame to jump to
+ if(gamepad.check_event(gamepad.BACK_PRESSED)){ //check for use of the pause menu
+ PauseOption choice = pause.pause_menu(gamepad, lcd, fps); //Get the user's selection
+ i = pause.brickbreaker_action(choice, gamepad, lcd, i, fps); //returns which frame to jump to
}
- brick.time_warning(gamepad, i, fps);
+ brick.time_warning(gamepad, i, fps); //Use LEDs to display how much time is left
}
- brick.end(gamepad, lcd);
- brick.write_high_scores();
+ brick.end(gamepad, lcd); //display the 'time up' screen with the user score
+ brick.write_high_scores(); //update high scores accordingly
}
void options_menu(){
- Option choice = BRIGHTNESS;
+ Option choice = BRIGHTNESS; //variable to store the selected option initialised to the top item in list
while(!(gamepad.check_event(gamepad.A_PRESSED))){
- lcd.clear();
- opt.display_options(lcd);
+ lcd.clear(); //keep rendering and updating the position of the
+ opt.display_options(lcd); //menu arrows until a choice is made
choice = opt.option_selection(gamepad, lcd);
lcd.refresh();
wait(0.2);
}
- if(choice == BRIGHTNESS){ opt.change_brightness(gamepad, lcd); }
- if(choice == BALL_SPEED){ opt.change_ball_speed(gamepad, lcd, ball); }
- if(choice == HIGH_SCORES){ opt.view_high_scores(gamepad, lcd); }
+ if(choice == BRIGHTNESS){ opt.change_brightness(gamepad, lcd); } //each menu option called by its
+ if(choice == BALL_SPEED){ opt.change_ball_speed(gamepad, lcd, ball); } //respective enum and a method in
+ if(choice == HIGH_SCORES){ opt.view_high_scores(gamepad, lcd); } //options engine processes the option
}