![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Dodging asteroids game.
Dependencies: 4DGL-uLCD-SE PinDetect SDFileSystem mbed wave_player
main.cpp
- Committer:
- dylanslack
- Date:
- 2016-03-14
- Revision:
- 0:3f73e98442ec
File content as of revision 0:3f73e98442ec:
#include "LSM9DS1.h" #include "uLCD_4DGL.h" #include "wave_player.h" #include "SDFileSystem.h" #include <math.h> #include <vector> #include <time.h> uLCD_4DGL uLCD(p28, p27, p30); SDFileSystem sd(p5, p6, p7, p8, "sd"); Serial pc(USBTX, USBRX); LSM9DS1 IMU(p9, p10, 0xD6, 0x3C); AnalogOut DACout(p18); wave_player waver(&DACout); FILE *explosion = fopen("/sd/explosion.wav", "r"); int score = 0; /** * The SpaceCraft class has a single position variable and * the methods required to move, draw, and clear a SpaceCraft * instance. */ class SpaceCraft { public: SpaceCraft(); void move(float); void draw(); void undraw(); int position; }; /** * Asteroids are similar to SpaceCrafts but are generated with * a random size, position, and velocity after being invoked. * The `isAlive` variable becomes false when the asteroid should * be reset, where it is given another random position, size, and * velocity. */ class Asteroid { public: Asteroid(); void move(int); void reset(); void fall(); void draw(); void undraw(); bool isAlive; int x, y, size, velocity; }; SpaceCraft::SpaceCraft() { position = 64; } Asteroid::Asteroid() { x = (rand() % 100) + 10; y = 0; size = (int)((rand() % 4) + 6); velocity = (int)((rand() % 3) + 1); isAlive = true; } // moves the space craft by clearing it, advancing it, then redrawing it void SpaceCraft::move(float x) { undraw(); position = (int)(64.0 - (x * 64.0)); draw(); } // moves the asteroid by clearing it, advancing it, then redrawing it void Asteroid::move(int posY) { if (y == posY) return; undraw(); y = posY; if (y >= 127) { isAlive = false; score++; } else { draw(); } } // moves the asteroid downward according to its velocity void Asteroid::fall() { move(y + velocity); } // resets the astroid by putting it back at the top with a random x coordinate void Asteroid::reset() { y = 0; x = (rand() % 100) + 10; velocity = (int)((rand() % 3) + 1); isAlive = true; } // draws the asteroid void Asteroid::draw() { int largeCraterRadius = (int)(floor((float)size / 3.0)); int largeCraterX = x - largeCraterRadius; int largeCraterY = y - largeCraterRadius; int smallCraterRadius = (int)(floor((float)size / 4.0)); int smallCraterX = x + largeCraterRadius; int smallCraterY = y + largeCraterRadius; uLCD.filled_circle(x, y, size, 0x909090); uLCD.circle(largeCraterX, largeCraterY, largeCraterRadius, 0x404040); uLCD.circle(smallCraterX, smallCraterY, smallCraterRadius, 0x404040); } // draws the space craft void SpaceCraft::draw() { int width = 12; int left = position - (width / 2); int right = position + (width / 2); int middle = left + (width / 2); // draw the space craft (blue triangle) uLCD.triangle(left, 120, middle, 106, right, 120, BLUE); // draw the flame (red triangle) uLCD.triangle(left + 4, 121, middle, 125, right - 4, 121, RED); } // clears the asteroid void Asteroid::undraw() { int largeCraterRadius = (int)(floor((float)size / 3.0)); int largeCraterX = x - largeCraterRadius; int largeCraterY = y - largeCraterRadius; int smallCraterRadius = (int)(floor((float)size / 4.0)); int smallCraterX = x + largeCraterRadius; int smallCraterY = y + largeCraterRadius; uLCD.filled_circle(x, y, size, BLACK); uLCD.circle(largeCraterX, largeCraterY, largeCraterRadius, BLACK); uLCD.circle(smallCraterX, smallCraterY, smallCraterRadius, BLACK); } // clears the space craft void SpaceCraft::undraw() { int width = 12; int left = position - (width / 2); int right = position + (width / 2); int middle = left + (width / 2); // clear the space craft (blue triangle) uLCD.triangle(left, 120, middle, 106, right, 120, BLACK); // clear the flame (red triangle) uLCD.triangle(left + 4, 121, middle, 125, right - 4, 121, BLACK); } /** * Returns true if there has been a collision between an asteroid and a ship. * This a very basic collision: it determines if any of the ship's vertices * interset with the asteroid's bounding circle. This fails for instances in * which the asteroid intesects with the edge of a ship but not one of the * vertices. * * This calculates vertex collision by comparing the circle's radius and the distance * between a vertex and the center of an asteroid. */ bool checkCollision(SpaceCraft ship, Asteroid asteroid) { // asteroid coordinates int asteroidCenterX = asteroid.x; int asteroidCenterY = asteroid.y; int asteroidRadius = asteroid.size; // ship coordinates int shipLeftX = ship.position - 6; int shipLeftY = 120; int shipRightX = ship.position + 6; int shipRightY = 120; int shipMiddleX = ship.position; int shipMiddleY = 106; // left vertex detection if (sqrt(pow(asteroidCenterX - shipLeftX, 2.0) + pow(asteroidCenterY - shipLeftY, 2.0)) <= asteroidRadius) return true; // right vertex detection if (sqrt(pow(asteroidCenterX - shipRightX, 2.0) + pow(asteroidCenterY - shipRightY, 2.0)) <= asteroidRadius) return true; // middle vertex detection if (sqrt(pow(asteroidCenterX - shipMiddleX, 2.0) + pow(asteroidCenterY - shipMiddleY, 2.0)) <= asteroidRadius) return true; return false; } SpaceCraft ship; vector<Asteroid> asteroids; int main() { float tilt; // don't forget to seed the rand function srand(time(NULL)); uLCD.reset(); uLCD.cls(); uLCD.background_color(BLACK); uLCD.printf("\nDodge asteroids!\n\r"); uLCD.printf("Loading..."); wait(1.0); uLCD.cls(); wait(1.0); // jack up the baudrate uLCD.baudrate(3000000); // initialize some asteroids Asteroid a, b, c, d; asteroids.push_back(a); asteroids.push_back(b); asteroids.push_back(c); asteroids.push_back(d); IMU.begin(); if (!IMU.begin()) { pc.printf("Failed to communicate with IMU.\n"); return 0; } IMU.calibrate(1); IMU.calibrateMag(0); if (explosion == NULL) { pc.printf("explosion.wav was not opened!\n"); return 0; } while(1) { while(!IMU.accelAvailable()); IMU.readAccel(); /** * `tilt` is the 'y' acceleration value, ranging between [-1.0, 1.0]. * * This variable will control the spacecraft's horizontal position. */ tilt = IMU.calcAccel(IMU.ay); for(size_t i = 0; i < asteroids.size(); i++) { asteroids[i].fall(); // reset the asteroid if it goes below the screen if (!asteroids[i].isAlive) { asteroids[i].reset(); } // play the explosion sound and end the game if there is a collision if (checkCollision(ship, asteroids[i])) { uLCD.background_color(RED); uLCD.textbackground_color(RED); waver.play(explosion); fseek(explosion, 0, SEEK_SET); uLCD.cls(); uLCD.color(WHITE); uLCD.text_width(3); uLCD.text_height(3); uLCD.printf("\nGame\nOVER\n\n"); uLCD.text_width(1); uLCD.text_height(1); uLCD.printf("Score: %d", score); return 0; } } // update the score uLCD.locate(0, 0); uLCD.printf("Score: %d", score); // move the ship based on the IMU's accelerometer reading ship.move(tilt); wait(0.01); } }