“Race Collision” is a one player game in which a truck has to avoid “particles” that appear on the road. By the use of the joystick, the player can guide themselves through the menu system to start the game. The truck is the main element of the game and it can be moved from side to side with the joystick. The road curves randomly from time to time and the player has to be careful to keep the truck within the road boundaries. Particles appear on the screen at random positions and 4 collisions lead to the end of the game.

Dependencies:   ELEC2645_JoystickLCD_LPC1768_2021

Committer:
alex_20
Date:
Thu May 06 12:04:45 2021 +0000
Revision:
9:6f060f495536
Parent:
8:1fc5e14b0db6
Race Collision for ELEC2645

Who changed what in which revision?

UserRevisionLine numberNew contents of line
eencae 0:be41a15e7a86 1 /* mbed Microcontroller Library
eencae 0:be41a15e7a86 2 * Copyright (c) 2019 ARM Limited
eencae 0:be41a15e7a86 3 * SPDX-License-Identifier: Apache-2.0
eencae 0:be41a15e7a86 4 */
eencae 0:be41a15e7a86 5
eencae 0:be41a15e7a86 6 #include "mbed.h"
alex_20 9:6f060f495536 7 #include "ShiftReg.h"
eencae 0:be41a15e7a86 8 #include "Joystick.h"
eencae 0:be41a15e7a86 9 #include "N5110.h"
alex_20 2:18fd28044860 10 #include "Road.h"
alex_20 6:40ef2030334c 11 #include "Car.h"
alex_20 4:def20a1665d1 12 #include "Utils.h"
alex_20 4:def20a1665d1 13 #include "Vector.h"
alex_20 8:1fc5e14b0db6 14 #include "Ball.h"
alex_20 9:6f060f495536 15 #include "Vector.h"
alex_20 9:6f060f495536 16 #include "GameEngine.h"
alex_20 9:6f060f495536 17 #include <stdlib.h>
alex_20 9:6f060f495536 18 #include <time.h>
eencae 0:be41a15e7a86 19
alex_20 1:2ae7a8b01771 20 // objects
alex_20 1:2ae7a8b01771 21 // BusOut leds(LED4,LED3,LED2,LED1);
eencae 0:be41a15e7a86 22
alex_20 6:40ef2030334c 23 N5110 lcd(p14,p8,p9,p10,p11,p13,p21);
alex_20 9:6f060f495536 24 InterruptIn button_A(p29);
alex_20 9:6f060f495536 25 DigitalIn button_B(p28);
alex_20 6:40ef2030334c 26 DigitalIn button_C(p27);
alex_20 9:6f060f495536 27 DigitalIn button_D(p26);
alex_20 9:6f060f495536 28 ShiftReg seven_seg;
eencae 0:be41a15e7a86 29
alex_20 6:40ef2030334c 30 // y x
alex_20 6:40ef2030334c 31 Joystick joystick(p20,p19);
alex_20 1:2ae7a8b01771 32
alex_20 2:18fd28044860 33 // B G R
alex_20 1:2ae7a8b01771 34 //BusOut leds(p22,p23,p24);
alex_20 1:2ae7a8b01771 35 // LSB MSB
alex_20 1:2ae7a8b01771 36
alex_20 2:18fd28044860 37 Road road;
alex_20 4:def20a1665d1 38 Utils utils;
alex_20 6:40ef2030334c 39 Car car;
alex_20 8:1fc5e14b0db6 40 Ball ball;
alex_20 9:6f060f495536 41 GameEngine game;
alex_20 9:6f060f495536 42 Ticker ticker;
alex_20 9:6f060f495536 43
alex_20 9:6f060f495536 44 // flag - must be volatile as changes within ISR
alex_20 9:6f060f495536 45 // g_ prefix makes it easier to distinguish it as global
alex_20 9:6f060f495536 46 volatile int g_timer_flag = 0;
alex_20 9:6f060f495536 47 volatile int g_buttonA_flag = 0;
alex_20 2:18fd28044860 48
alex_20 4:def20a1665d1 49 #define speed 0.01
alex_20 8:1fc5e14b0db6 50 #define road_speed 0.016
alex_20 6:40ef2030334c 51 #define car_speed 0.2
alex_20 6:40ef2030334c 52
alex_20 1:2ae7a8b01771 53 // functions
alex_20 1:2ae7a8b01771 54 void init_buttons();
alex_20 9:6f060f495536 55 void init();
alex_20 9:6f060f495536 56 void render();
alex_20 9:6f060f495536 57 void menu();
alex_20 9:6f060f495536 58 void instructions();
alex_20 9:6f060f495536 59 void pause();
alex_20 9:6f060f495536 60 void game_over();
alex_20 9:6f060f495536 61 void draw_arrow(int x, int y);
alex_20 9:6f060f495536 62 void timer_isr();
alex_20 9:6f060f495536 63 void buttonA_isr();
alex_20 9:6f060f495536 64 void display_lives(int lives);
eencae 0:be41a15e7a86 65
eencae 0:be41a15e7a86 66 int main()
eencae 0:be41a15e7a86 67 {
alex_20 9:6f060f495536 68 button_A.rise(&buttonA_isr);
alex_20 9:6f060f495536 69 init_buttons();
alex_20 9:6f060f495536 70 int state = 0; // set inital state
alex_20 9:6f060f495536 71 init();
alex_20 9:6f060f495536 72 // welcome();
alex_20 9:6f060f495536 73 int up_down = 17;
alex_20 9:6f060f495536 74 float number_1 = 0;
alex_20 9:6f060f495536 75 float number_2 = 0;
alex_20 9:6f060f495536 76 int lives = 4;
alex_20 9:6f060f495536 77 int old_collision = 0;
alex_20 9:6f060f495536 78 display_lives(0);
alex_20 9:6f060f495536 79
alex_20 9:6f060f495536 80 // set-up the ticker so that the ISR it is called every 5 seconds
alex_20 9:6f060f495536 81 ticker.attach(&timer_isr,5);
alex_20 6:40ef2030334c 82
alex_20 1:2ae7a8b01771 83 while(1) {
alex_20 1:2ae7a8b01771 84 lcd.clear();
alex_20 9:6f060f495536 85 Vector2D coord = joystick.get_mapped_coord();
alex_20 9:6f060f495536 86 switch(state) {
alex_20 4:def20a1665d1 87
alex_20 9:6f060f495536 88 case 0: // Main Menu
alex_20 9:6f060f495536 89 {
alex_20 9:6f060f495536 90 menu();
alex_20 9:6f060f495536 91 lives = 4;
alex_20 9:6f060f495536 92 display_lives(0);
alex_20 9:6f060f495536 93 if(coord.y >= 0.5) {
alex_20 9:6f060f495536 94 up_down = 17;
alex_20 9:6f060f495536 95 }
alex_20 9:6f060f495536 96
alex_20 9:6f060f495536 97 if(coord.y <= -0.5) {
alex_20 9:6f060f495536 98 up_down = 25;
alex_20 9:6f060f495536 99 }
alex_20 9:6f060f495536 100
alex_20 9:6f060f495536 101 draw_arrow(2,up_down);
alex_20 9:6f060f495536 102
alex_20 9:6f060f495536 103 if(g_buttonA_flag) {
alex_20 9:6f060f495536 104 if(up_down == 17){
alex_20 9:6f060f495536 105 state = 1;
alex_20 9:6f060f495536 106 g_buttonA_flag = 0;
alex_20 9:6f060f495536 107 }
alex_20 9:6f060f495536 108 if(up_down == 25) {
alex_20 9:6f060f495536 109 state = 2;
alex_20 9:6f060f495536 110 g_buttonA_flag = 0;
alex_20 9:6f060f495536 111 }
alex_20 9:6f060f495536 112 }
alex_20 9:6f060f495536 113 break;
alex_20 6:40ef2030334c 114 }
alex_20 9:6f060f495536 115
alex_20 9:6f060f495536 116
alex_20 9:6f060f495536 117 case 1: // Actual Game
alex_20 9:6f060f495536 118 {
alex_20 9:6f060f495536 119 game.update(coord.x);
alex_20 9:6f060f495536 120
alex_20 9:6f060f495536 121 // check if flag is set i.e. interrupt has occured
alex_20 9:6f060f495536 122 if (g_timer_flag) {
alex_20 9:6f060f495536 123 g_timer_flag = 0; // if it has, clear the flag
alex_20 9:6f060f495536 124
alex_20 9:6f060f495536 125 // generate random road or ball
alex_20 9:6f060f495536 126 // initialize random seed:
alex_20 9:6f060f495536 127 srand (time(NULL));
alex_20 9:6f060f495536 128
alex_20 9:6f060f495536 129 number_1 = (rand() % 20 + 1) - 10;
alex_20 9:6f060f495536 130 number_2 = (static_cast <float> (rand()) / (static_cast <float> (RAND_MAX/10.0))) - 5.0;
alex_20 9:6f060f495536 131 game.reset_ball();
alex_20 6:40ef2030334c 132 }
alex_20 9:6f060f495536 133
alex_20 9:6f060f495536 134 game.generate_ball(number_1);
alex_20 9:6f060f495536 135 game.generate_road(number_2);
alex_20 9:6f060f495536 136
alex_20 9:6f060f495536 137 // put the MCU to sleep until an interrupt wakes it up
alex_20 9:6f060f495536 138 sleep();
alex_20 9:6f060f495536 139 render();
alex_20 9:6f060f495536 140 display_lives(lives);
alex_20 9:6f060f495536 141
alex_20 9:6f060f495536 142 int collision = game.check_collision();
alex_20 9:6f060f495536 143 if(collision == 1 && old_collision == 0) {
alex_20 9:6f060f495536 144 lives--;
alex_20 9:6f060f495536 145 if (lives == 0) {
alex_20 9:6f060f495536 146 state = 4;
alex_20 9:6f060f495536 147 }
alex_20 9:6f060f495536 148 }
alex_20 9:6f060f495536 149
alex_20 9:6f060f495536 150 old_collision = collision;
alex_20 9:6f060f495536 151
alex_20 9:6f060f495536 152 if(g_buttonA_flag) {
alex_20 9:6f060f495536 153 state = 3;
alex_20 9:6f060f495536 154 g_buttonA_flag = 0;
alex_20 9:6f060f495536 155 }
alex_20 9:6f060f495536 156 break;
alex_20 9:6f060f495536 157 }
alex_20 9:6f060f495536 158
alex_20 9:6f060f495536 159
alex_20 9:6f060f495536 160 case 2: // Instructions
alex_20 9:6f060f495536 161 {
alex_20 9:6f060f495536 162 instructions();
alex_20 9:6f060f495536 163 if(g_buttonA_flag) {
alex_20 9:6f060f495536 164 state = 0;
alex_20 9:6f060f495536 165 g_buttonA_flag = 0;
alex_20 6:40ef2030334c 166 }
alex_20 9:6f060f495536 167 break;
alex_20 9:6f060f495536 168 }
alex_20 9:6f060f495536 169
alex_20 9:6f060f495536 170
alex_20 9:6f060f495536 171 case 3: // Pause Menu
alex_20 9:6f060f495536 172 {
alex_20 9:6f060f495536 173 pause();
alex_20 9:6f060f495536 174 if(coord.y >= 0.5) {
alex_20 9:6f060f495536 175 up_down = 17;
alex_20 6:40ef2030334c 176 }
alex_20 9:6f060f495536 177 if(coord.y <= -0.5) {
alex_20 9:6f060f495536 178 up_down = 25;
alex_20 9:6f060f495536 179 }
alex_20 9:6f060f495536 180
alex_20 9:6f060f495536 181 draw_arrow(2,up_down);
alex_20 9:6f060f495536 182 if(g_buttonA_flag) {
alex_20 9:6f060f495536 183 if(up_down == 17){
alex_20 9:6f060f495536 184 state = 1;
alex_20 9:6f060f495536 185 g_buttonA_flag = 0;
alex_20 9:6f060f495536 186 }
alex_20 9:6f060f495536 187 if(up_down == 25) {
alex_20 9:6f060f495536 188 state = 0;
alex_20 9:6f060f495536 189 g_buttonA_flag = 0;
alex_20 9:6f060f495536 190 }
alex_20 9:6f060f495536 191 }
alex_20 9:6f060f495536 192 break;
alex_20 9:6f060f495536 193 }
alex_20 9:6f060f495536 194
alex_20 9:6f060f495536 195 case 4: // Game over
alex_20 9:6f060f495536 196 {
alex_20 9:6f060f495536 197 game_over();
alex_20 9:6f060f495536 198 if(g_buttonA_flag) {
alex_20 9:6f060f495536 199 state = 0;
alex_20 9:6f060f495536 200 g_buttonA_flag = 0;
alex_20 9:6f060f495536 201 }
alex_20 9:6f060f495536 202 break;
alex_20 9:6f060f495536 203 }
alex_20 6:40ef2030334c 204 }
alex_20 9:6f060f495536 205 sleep();
alex_20 9:6f060f495536 206 lcd.refresh();
eencae 0:be41a15e7a86 207 }
eencae 0:be41a15e7a86 208 }
alex_20 1:2ae7a8b01771 209
alex_20 1:2ae7a8b01771 210 void init_buttons()
alex_20 1:2ae7a8b01771 211 {
alex_20 1:2ae7a8b01771 212 // PCB has external pull-down resistors so turn the internal ones off
alex_20 1:2ae7a8b01771 213 // (default for DigitalIn)
alex_20 1:2ae7a8b01771 214 button_A.mode(PullNone);
alex_20 9:6f060f495536 215 button_B.mode(PullNone);
alex_20 1:2ae7a8b01771 216 button_C.mode(PullNone);
alex_20 9:6f060f495536 217 button_D.mode(PullNone);
alex_20 9:6f060f495536 218 }
alex_20 9:6f060f495536 219
alex_20 9:6f060f495536 220
alex_20 9:6f060f495536 221 void init() {
alex_20 9:6f060f495536 222 seven_seg.write(0x00);
alex_20 9:6f060f495536 223 lcd.init();
alex_20 9:6f060f495536 224 joystick.init();
alex_20 9:6f060f495536 225 lcd.setContrast(0.55);
alex_20 9:6f060f495536 226
alex_20 9:6f060f495536 227 std::vector<Vector2Df> curve_point;
alex_20 9:6f060f495536 228 Vector2Df point = {-20.0,-50.0};
alex_20 9:6f060f495536 229 curve_point.push_back(point);
alex_20 9:6f060f495536 230
alex_20 9:6f060f495536 231 game.init(0.0, // road direction
alex_20 9:6f060f495536 232 0.0, // road inclination
alex_20 9:6f060f495536 233 4, // ball radius
alex_20 9:6f060f495536 234 curve_point, // points from ball path
alex_20 9:6f060f495536 235 0, // car direction
alex_20 9:6f060f495536 236 0, // car magnitude
alex_20 9:6f060f495536 237 38.0, // car start position
alex_20 9:6f060f495536 238 0.0, // offset
alex_20 9:6f060f495536 239 0.0, // car_turn
alex_20 9:6f060f495536 240 0.0); // ball_it
alex_20 9:6f060f495536 241 }
alex_20 9:6f060f495536 242
alex_20 9:6f060f495536 243 void menu() {
alex_20 9:6f060f495536 244 lcd.printString("MAIN MENU",15,0);
alex_20 9:6f060f495536 245 lcd.printString("Start Game",10,2);
alex_20 9:6f060f495536 246 lcd.printString("Instructions",10,3);
alex_20 9:6f060f495536 247 lcd.printString("Press A",20,5);
alex_20 9:6f060f495536 248 }
alex_20 9:6f060f495536 249
alex_20 9:6f060f495536 250 void instructions() {
alex_20 9:6f060f495536 251 lcd.printString("INSTRUCTIONS",6,0);
alex_20 9:6f060f495536 252 lcd.printString("Use joystick",6,1);
alex_20 9:6f060f495536 253 lcd.printString("to move",21,2);
alex_20 9:6f060f495536 254 lcd.printString("Press A to",13,4);
alex_20 9:6f060f495536 255 lcd.printString("pause or exit",4,5);
alex_20 9:6f060f495536 256 display_lives(0);
alex_20 9:6f060f495536 257 }
alex_20 9:6f060f495536 258
alex_20 9:6f060f495536 259 void pause() {
alex_20 9:6f060f495536 260 lcd.printString("PAUSE",27,0);
alex_20 9:6f060f495536 261 lcd.printString("Back to game",10,2);
alex_20 9:6f060f495536 262 lcd.printString("Back to menu",10,3);
alex_20 9:6f060f495536 263 }
alex_20 9:6f060f495536 264
alex_20 9:6f060f495536 265 void game_over() {
alex_20 9:6f060f495536 266 lcd.printString("GAME OVER",16,1);
alex_20 9:6f060f495536 267 lcd.printString("Don't collide!",1,2);
alex_20 9:6f060f495536 268 lcd.printString("Press A",20,5);
alex_20 9:6f060f495536 269 }
alex_20 9:6f060f495536 270
alex_20 9:6f060f495536 271 void render() {
alex_20 9:6f060f495536 272 game.draw(lcd, utils);
alex_20 9:6f060f495536 273 }
alex_20 9:6f060f495536 274
alex_20 9:6f060f495536 275 void draw_arrow(int x, int y) {
alex_20 9:6f060f495536 276 const int arrow[5][7] = {
alex_20 9:6f060f495536 277 { 0, 0, 0, 0, 1, 0, 0 },
alex_20 9:6f060f495536 278 { 1, 1, 1, 1, 1, 1, 0 },
alex_20 9:6f060f495536 279 { 1, 1, 1, 1, 1, 1, 1 },
alex_20 9:6f060f495536 280 { 1, 1, 1, 1, 1, 1, 0 },
alex_20 9:6f060f495536 281 { 0, 0, 0, 0, 1, 0, 0 },
alex_20 9:6f060f495536 282 };
alex_20 9:6f060f495536 283 lcd.drawSprite(x,y,5,7,(int *)arrow);
alex_20 9:6f060f495536 284 }
alex_20 9:6f060f495536 285
alex_20 9:6f060f495536 286 // time-triggered interrupt
alex_20 9:6f060f495536 287 void timer_isr() {
alex_20 9:6f060f495536 288 g_timer_flag = 1; // set flag in ISR
alex_20 9:6f060f495536 289 }
alex_20 9:6f060f495536 290
alex_20 9:6f060f495536 291 // Button A event-triggered interrupt
alex_20 9:6f060f495536 292 void buttonA_isr() {
alex_20 9:6f060f495536 293 g_buttonA_flag = 1; // set flag in ISR
alex_20 9:6f060f495536 294 }
alex_20 9:6f060f495536 295
alex_20 9:6f060f495536 296 void display_lives(int lives) {
alex_20 9:6f060f495536 297 if (lives == 4) {
alex_20 9:6f060f495536 298 lcd.printString("Lives: 4",0,0);
alex_20 9:6f060f495536 299 seven_seg.write(0x66);
alex_20 9:6f060f495536 300 } else if (lives == 3) {
alex_20 9:6f060f495536 301 lcd.printString("Lives: 3",0,0);
alex_20 9:6f060f495536 302 seven_seg.write(0x4F);
alex_20 9:6f060f495536 303 } else if (lives == 2) {
alex_20 9:6f060f495536 304 lcd.printString("Lives: 2",0,0);
alex_20 9:6f060f495536 305 seven_seg.write(0x5B);
alex_20 9:6f060f495536 306 } else if (lives == 1) {
alex_20 9:6f060f495536 307 lcd.printString("Lives: 1",0,0);
alex_20 9:6f060f495536 308 seven_seg.write(0x06);
alex_20 9:6f060f495536 309 } else {
alex_20 9:6f060f495536 310 seven_seg.write(0x3F);
alex_20 9:6f060f495536 311 }
alex_20 1:2ae7a8b01771 312 }