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: 4DGL-uLCD-SE PinDetect SDFileSystem mbed wave_player
main.cpp
00001 #include "LSM9DS1.h" 00002 #include "uLCD_4DGL.h" 00003 #include "wave_player.h" 00004 #include "SDFileSystem.h" 00005 #include <math.h> 00006 #include <vector> 00007 #include <time.h> 00008 00009 uLCD_4DGL uLCD(p28, p27, p30); 00010 SDFileSystem sd(p5, p6, p7, p8, "sd"); 00011 Serial pc(USBTX, USBRX); 00012 LSM9DS1 IMU(p9, p10, 0xD6, 0x3C); 00013 AnalogOut DACout(p18); 00014 wave_player waver(&DACout); 00015 00016 FILE *explosion = fopen("/sd/explosion.wav", "r"); 00017 00018 int score = 0; 00019 00020 /** 00021 * The SpaceCraft class has a single position variable and 00022 * the methods required to move, draw, and clear a SpaceCraft 00023 * instance. 00024 */ 00025 class SpaceCraft { 00026 public: 00027 SpaceCraft(); 00028 void move(float); 00029 void draw(); 00030 void undraw(); 00031 int position; 00032 }; 00033 00034 /** 00035 * Asteroids are similar to SpaceCrafts but are generated with 00036 * a random size, position, and velocity after being invoked. 00037 * The `isAlive` variable becomes false when the asteroid should 00038 * be reset, where it is given another random position, size, and 00039 * velocity. 00040 */ 00041 class Asteroid { 00042 public: 00043 Asteroid(); 00044 void move(int); 00045 void reset(); 00046 void fall(); 00047 void draw(); 00048 void undraw(); 00049 bool isAlive; 00050 int x, y, size, velocity; 00051 }; 00052 00053 SpaceCraft::SpaceCraft() { 00054 position = 64; 00055 } 00056 00057 Asteroid::Asteroid() { 00058 x = (rand() % 100) + 10; 00059 y = 0; 00060 size = (int)((rand() % 4) + 6); 00061 velocity = (int)((rand() % 3) + 1); 00062 isAlive = true; 00063 } 00064 00065 // moves the space craft by clearing it, advancing it, then redrawing it 00066 void SpaceCraft::move(float x) { 00067 undraw(); 00068 position = (int)(64.0 - (x * 64.0)); 00069 draw(); 00070 } 00071 00072 // moves the asteroid by clearing it, advancing it, then redrawing it 00073 void Asteroid::move(int posY) { 00074 if (y == posY) return; 00075 00076 undraw(); 00077 y = posY; 00078 00079 if (y >= 127) { 00080 isAlive = false; 00081 score++; 00082 } else { 00083 draw(); 00084 } 00085 } 00086 00087 // moves the asteroid downward according to its velocity 00088 void Asteroid::fall() { 00089 move(y + velocity); 00090 } 00091 00092 // resets the astroid by putting it back at the top with a random x coordinate 00093 void Asteroid::reset() { 00094 y = 0; 00095 x = (rand() % 100) + 10; 00096 velocity = (int)((rand() % 3) + 1); 00097 isAlive = true; 00098 } 00099 00100 // draws the asteroid 00101 void Asteroid::draw() { 00102 int largeCraterRadius = (int)(floor((float)size / 3.0)); 00103 int largeCraterX = x - largeCraterRadius; 00104 int largeCraterY = y - largeCraterRadius; 00105 00106 int smallCraterRadius = (int)(floor((float)size / 4.0)); 00107 int smallCraterX = x + largeCraterRadius; 00108 int smallCraterY = y + largeCraterRadius; 00109 00110 uLCD.filled_circle(x, y, size, 0x909090); 00111 uLCD.circle(largeCraterX, largeCraterY, largeCraterRadius, 0x404040); 00112 uLCD.circle(smallCraterX, smallCraterY, smallCraterRadius, 0x404040); 00113 } 00114 00115 // draws the space craft 00116 void SpaceCraft::draw() { 00117 int width = 12; 00118 int left = position - (width / 2); 00119 int right = position + (width / 2); 00120 int middle = left + (width / 2); 00121 00122 // draw the space craft (blue triangle) 00123 uLCD.triangle(left, 120, middle, 106, right, 120, BLUE); 00124 00125 // draw the flame (red triangle) 00126 uLCD.triangle(left + 4, 121, middle, 125, right - 4, 121, RED); 00127 } 00128 00129 // clears the asteroid 00130 void Asteroid::undraw() { 00131 int largeCraterRadius = (int)(floor((float)size / 3.0)); 00132 int largeCraterX = x - largeCraterRadius; 00133 int largeCraterY = y - largeCraterRadius; 00134 00135 int smallCraterRadius = (int)(floor((float)size / 4.0)); 00136 int smallCraterX = x + largeCraterRadius; 00137 int smallCraterY = y + largeCraterRadius; 00138 00139 uLCD.filled_circle(x, y, size, BLACK); 00140 uLCD.circle(largeCraterX, largeCraterY, largeCraterRadius, BLACK); 00141 uLCD.circle(smallCraterX, smallCraterY, smallCraterRadius, BLACK); 00142 } 00143 00144 // clears the space craft 00145 void SpaceCraft::undraw() { 00146 int width = 12; 00147 int left = position - (width / 2); 00148 int right = position + (width / 2); 00149 int middle = left + (width / 2); 00150 00151 // clear the space craft (blue triangle) 00152 uLCD.triangle(left, 120, middle, 106, right, 120, BLACK); 00153 00154 // clear the flame (red triangle) 00155 uLCD.triangle(left + 4, 121, middle, 125, right - 4, 121, BLACK); 00156 } 00157 00158 /** 00159 * Returns true if there has been a collision between an asteroid and a ship. 00160 * This a very basic collision: it determines if any of the ship's vertices 00161 * interset with the asteroid's bounding circle. This fails for instances in 00162 * which the asteroid intesects with the edge of a ship but not one of the 00163 * vertices. 00164 * 00165 * This calculates vertex collision by comparing the circle's radius and the distance 00166 * between a vertex and the center of an asteroid. 00167 */ 00168 bool checkCollision(SpaceCraft ship, Asteroid asteroid) { 00169 // asteroid coordinates 00170 int asteroidCenterX = asteroid.x; 00171 int asteroidCenterY = asteroid.y; 00172 int asteroidRadius = asteroid.size; 00173 00174 // ship coordinates 00175 int shipLeftX = ship.position - 6; 00176 int shipLeftY = 120; 00177 int shipRightX = ship.position + 6; 00178 int shipRightY = 120; 00179 int shipMiddleX = ship.position; 00180 int shipMiddleY = 106; 00181 00182 // left vertex detection 00183 if (sqrt(pow(asteroidCenterX - shipLeftX, 2.0) + pow(asteroidCenterY - shipLeftY, 2.0)) <= asteroidRadius) 00184 return true; 00185 00186 // right vertex detection 00187 if (sqrt(pow(asteroidCenterX - shipRightX, 2.0) + pow(asteroidCenterY - shipRightY, 2.0)) <= asteroidRadius) 00188 return true; 00189 00190 // middle vertex detection 00191 if (sqrt(pow(asteroidCenterX - shipMiddleX, 2.0) + pow(asteroidCenterY - shipMiddleY, 2.0)) <= asteroidRadius) 00192 return true; 00193 00194 return false; 00195 } 00196 00197 SpaceCraft ship; 00198 vector<Asteroid> asteroids; 00199 00200 int main() { 00201 float tilt; 00202 00203 // don't forget to seed the rand function 00204 srand(time(NULL)); 00205 00206 uLCD.reset(); 00207 uLCD.cls(); 00208 uLCD.background_color(BLACK); 00209 uLCD.printf("\nDodge asteroids!\n\r"); 00210 uLCD.printf("Loading..."); 00211 00212 wait(1.0); 00213 uLCD.cls(); 00214 wait(1.0); 00215 00216 // jack up the baudrate 00217 uLCD.baudrate(3000000); 00218 00219 // initialize some asteroids 00220 Asteroid a, b, c, d; 00221 asteroids.push_back(a); 00222 asteroids.push_back(b); 00223 asteroids.push_back(c); 00224 asteroids.push_back(d); 00225 00226 IMU.begin(); 00227 00228 if (!IMU.begin()) { 00229 pc.printf("Failed to communicate with IMU.\n"); 00230 return 0; 00231 } 00232 00233 IMU.calibrate(1); 00234 IMU.calibrateMag(0); 00235 00236 if (explosion == NULL) { 00237 pc.printf("explosion.wav was not opened!\n"); 00238 return 0; 00239 } 00240 00241 while(1) { 00242 while(!IMU.accelAvailable()); 00243 IMU.readAccel(); 00244 00245 /** 00246 * `tilt` is the 'y' acceleration value, ranging between [-1.0, 1.0]. 00247 * 00248 * This variable will control the spacecraft's horizontal position. 00249 */ 00250 tilt = IMU.calcAccel(IMU.ay); 00251 00252 for(size_t i = 0; i < asteroids.size(); i++) { 00253 asteroids[i].fall(); 00254 00255 // reset the asteroid if it goes below the screen 00256 if (!asteroids[i].isAlive) { 00257 asteroids[i].reset(); 00258 } 00259 00260 // play the explosion sound and end the game if there is a collision 00261 if (checkCollision(ship, asteroids[i])) { 00262 uLCD.background_color(RED); 00263 uLCD.textbackground_color(RED); 00264 waver.play(explosion); 00265 fseek(explosion, 0, SEEK_SET); 00266 uLCD.cls(); 00267 uLCD.color(WHITE); 00268 uLCD.text_width(3); 00269 uLCD.text_height(3); 00270 uLCD.printf("\nGame\nOVER\n\n"); 00271 uLCD.text_width(1); 00272 uLCD.text_height(1); 00273 uLCD.printf("Score: %d", score); 00274 return 0; 00275 } 00276 } 00277 00278 // update the score 00279 uLCD.locate(0, 0); 00280 uLCD.printf("Score: %d", score); 00281 00282 // move the ship based on the IMU's accelerometer reading 00283 ship.move(tilt); 00284 wait(0.01); 00285 } 00286 }
Generated on Thu Jul 14 2022 21:02:14 by
1.7.2