Some random attempts at programming the retro console

Dependencies:   LCD_ST7735 mbed

Fork of RETRO_Pong_Mod by G. Andrew Duthie

Committer:
john_ghielec
Date:
Fri Nov 21 20:13:10 2014 +0000
Revision:
2:6ab46f2e851a
Parent:
1:cd8a3926f263
Child:
3:2f09c90a732d
Added an accelerometer graph when you press the robot.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
john_ghielec 1:cd8a3926f263 1 #include "Game.h"
john_ghielec 1:cd8a3926f263 2
john_ghielec 1:cd8a3926f263 3 const char* Game::LOSE_1 = "You lose.";
john_ghielec 1:cd8a3926f263 4 const char* Game::LOSE_2 = "Press ship to restart.";
john_ghielec 2:6ab46f2e851a 5 const char* Game::SPLASH_1 = "Press ship to start.";
john_ghielec 2:6ab46f2e851a 6 const char* Game::SPLASH_2 = "Press robot to switch.";
john_ghielec 1:cd8a3926f263 7
john_ghielec 1:cd8a3926f263 8 Game::Game() : left(P0_14, PullUp), right(P0_11, PullUp), down(P0_12, PullUp), up(P0_13, PullUp), square(P0_16, PullUp), circle(P0_1, PullUp), led1(P0_9), led2(P0_8), pwm(P0_18), ain(P0_15), i2c(P0_5, P0_4) {
john_ghielec 1:cd8a3926f263 9 srand(this->ain.read_u16());
john_ghielec 1:cd8a3926f263 10
john_ghielec 2:6ab46f2e851a 11 this->lastUp = false;
john_ghielec 2:6ab46f2e851a 12 this->lastDown = false;
john_ghielec 2:6ab46f2e851a 13 this->mode = true;
john_ghielec 2:6ab46f2e851a 14
john_ghielec 2:6ab46f2e851a 15 this->i2c.frequency(400);
john_ghielec 2:6ab46f2e851a 16 this->writeRegister(0x2A, 0x01);
john_ghielec 2:6ab46f2e851a 17
john_ghielec 2:6ab46f2e851a 18 this->colors[0] = DisplayN18::RED;
john_ghielec 2:6ab46f2e851a 19 this->colors[1] = DisplayN18::GREEN;
john_ghielec 2:6ab46f2e851a 20 this->colors[2] = DisplayN18::BLUE;
john_ghielec 2:6ab46f2e851a 21
john_ghielec 1:cd8a3926f263 22 this->initialize();
john_ghielec 1:cd8a3926f263 23 }
john_ghielec 1:cd8a3926f263 24
john_ghielec 2:6ab46f2e851a 25 void Game::readRegisters(char address, char* buffer, int len) {
john_ghielec 2:6ab46f2e851a 26 this->i2c.write(Game::I2C_ADDR, &address, 1, true);
john_ghielec 2:6ab46f2e851a 27 this->i2c.read(Game::I2C_ADDR | 1, buffer, len);
john_ghielec 2:6ab46f2e851a 28 }
john_ghielec 2:6ab46f2e851a 29
john_ghielec 2:6ab46f2e851a 30 int Game::writeRegister(char address, char value) {
john_ghielec 2:6ab46f2e851a 31 char buffer[2] = { address, value };
john_ghielec 2:6ab46f2e851a 32
john_ghielec 2:6ab46f2e851a 33 return this->i2c.write(Game::I2C_ADDR, buffer, 2);
john_ghielec 2:6ab46f2e851a 34 }
john_ghielec 2:6ab46f2e851a 35
john_ghielec 2:6ab46f2e851a 36 double Game::convert(char* buffer) {
john_ghielec 2:6ab46f2e851a 37 double val = ((buffer[0] << 2) | (buffer[1] >> 6));
john_ghielec 2:6ab46f2e851a 38
john_ghielec 2:6ab46f2e851a 39 if (val > 511.0)
john_ghielec 2:6ab46f2e851a 40 val -= 1024.0;
john_ghielec 2:6ab46f2e851a 41
john_ghielec 2:6ab46f2e851a 42 return val / 512.0;
john_ghielec 2:6ab46f2e851a 43 }
john_ghielec 2:6ab46f2e851a 44
john_ghielec 2:6ab46f2e851a 45 void Game::getXYZ(double& x, double& y, double& z) {
john_ghielec 2:6ab46f2e851a 46 char buffer[6];
john_ghielec 2:6ab46f2e851a 47
john_ghielec 2:6ab46f2e851a 48 this->readRegisters(0x01, buffer, 6);
john_ghielec 2:6ab46f2e851a 49
john_ghielec 2:6ab46f2e851a 50 x = this->convert(buffer);
john_ghielec 2:6ab46f2e851a 51 y = this->convert(buffer + 2);
john_ghielec 2:6ab46f2e851a 52 z = this->convert(buffer + 4);
john_ghielec 2:6ab46f2e851a 53 }
john_ghielec 2:6ab46f2e851a 54
john_ghielec 2:6ab46f2e851a 55 void Game::printDouble(double value, int x, int y) {
john_ghielec 2:6ab46f2e851a 56 char buffer[10];
john_ghielec 2:6ab46f2e851a 57 int len = sprintf(buffer, "%.1f", value);
john_ghielec 2:6ab46f2e851a 58
john_ghielec 2:6ab46f2e851a 59 this->disp.drawString(x, y, buffer, DisplayN18::WHITE, DisplayN18::BLACK);
john_ghielec 2:6ab46f2e851a 60 }
john_ghielec 2:6ab46f2e851a 61
john_ghielec 2:6ab46f2e851a 62 void Game::drawAxes() {
john_ghielec 2:6ab46f2e851a 63 for (int i = 0; i < 3; i++) {
john_ghielec 2:6ab46f2e851a 64 this->disp.drawLine(0, i * (Game::GRAPH_HEIGHT + Game::GRAPH_SPACING), 0, i * (Game::GRAPH_HEIGHT + Game::GRAPH_SPACING) + Game::GRAPH_HEIGHT, DisplayN18::WHITE);
john_ghielec 2:6ab46f2e851a 65 this->disp.drawLine(0, i * (Game::GRAPH_HEIGHT + Game::GRAPH_SPACING) + Game::GRAPH_HEIGHT / 2, DisplayN18::WIDTH, i * (Game::GRAPH_HEIGHT + Game::GRAPH_SPACING) + Game::GRAPH_HEIGHT / 2, DisplayN18::WHITE);
john_ghielec 2:6ab46f2e851a 66 }
john_ghielec 2:6ab46f2e851a 67 }
john_ghielec 2:6ab46f2e851a 68
john_ghielec 2:6ab46f2e851a 69 void Game::drawPoint(int axis, double value) {
john_ghielec 2:6ab46f2e851a 70 if (value < -1.0)
john_ghielec 2:6ab46f2e851a 71 value = -1.0;
john_ghielec 2:6ab46f2e851a 72
john_ghielec 2:6ab46f2e851a 73 if (value > 1.0)
john_ghielec 2:6ab46f2e851a 74 value = 1.0;
john_ghielec 2:6ab46f2e851a 75
john_ghielec 2:6ab46f2e851a 76 value += 1.0;
john_ghielec 2:6ab46f2e851a 77 value /= 2.0;
john_ghielec 2:6ab46f2e851a 78 value = 1.0 - value;
john_ghielec 2:6ab46f2e851a 79 value *= Game::GRAPH_HEIGHT;
john_ghielec 2:6ab46f2e851a 80
john_ghielec 2:6ab46f2e851a 81 this->disp.setPixel(this->graphX, axis * (Game::GRAPH_HEIGHT + Game::GRAPH_SPACING) + (int)value, this->colors[axis]);
john_ghielec 2:6ab46f2e851a 82 }
john_ghielec 2:6ab46f2e851a 83
john_ghielec 2:6ab46f2e851a 84 void Game::checkGraphReset() {
john_ghielec 2:6ab46f2e851a 85 if (this->graphX > DisplayN18::WIDTH) {
john_ghielec 2:6ab46f2e851a 86 this->graphX = 0;
john_ghielec 2:6ab46f2e851a 87 this->disp.clear();
john_ghielec 2:6ab46f2e851a 88 this->drawAxes();
john_ghielec 2:6ab46f2e851a 89 }
john_ghielec 2:6ab46f2e851a 90 }
john_ghielec 2:6ab46f2e851a 91
john_ghielec 1:cd8a3926f263 92 void Game::initialize() {
john_ghielec 1:cd8a3926f263 93 this->initializeBall();
john_ghielec 1:cd8a3926f263 94
john_ghielec 1:cd8a3926f263 95 this->paddleX = DisplayN18::WIDTH / 2 - Game::PADDLE_WIDTH / 2;
john_ghielec 1:cd8a3926f263 96 this->pwmTicksLeft = 0;
john_ghielec 1:cd8a3926f263 97 this->lives = 4;
john_ghielec 1:cd8a3926f263 98
john_ghielec 1:cd8a3926f263 99 this->pwm.period_ms(1);
john_ghielec 1:cd8a3926f263 100 this->pwm.write(0.00);
john_ghielec 1:cd8a3926f263 101
john_ghielec 1:cd8a3926f263 102 this->disp.clear();
john_ghielec 1:cd8a3926f263 103 }
john_ghielec 1:cd8a3926f263 104
john_ghielec 1:cd8a3926f263 105 void Game::initializeBall() {
john_ghielec 1:cd8a3926f263 106 this->ballX = DisplayN18::WIDTH / 2 - Game::BALL_RADIUS;
john_ghielec 1:cd8a3926f263 107 this->ballY = DisplayN18::HEIGHT / 4 - Game::BALL_RADIUS;
john_ghielec 1:cd8a3926f263 108
john_ghielec 2:6ab46f2e851a 109 this->ballSpeedX = rand() % 2 ? 1 : -1;
john_ghielec 2:6ab46f2e851a 110 this->ballSpeedY = rand() % 2 ? 1 : -1;
john_ghielec 2:6ab46f2e851a 111 }
john_ghielec 2:6ab46f2e851a 112
john_ghielec 2:6ab46f2e851a 113 void Game::tick() {
john_ghielec 2:6ab46f2e851a 114 this->checkButtons();
john_ghielec 1:cd8a3926f263 115
john_ghielec 2:6ab46f2e851a 116 if (this->mode) {
john_ghielec 2:6ab46f2e851a 117 this->clearPaddle();
john_ghielec 2:6ab46f2e851a 118 this->clearBall();
john_ghielec 2:6ab46f2e851a 119
john_ghielec 2:6ab46f2e851a 120 this->updatePaddle();
john_ghielec 2:6ab46f2e851a 121 this->updateBall();
john_ghielec 1:cd8a3926f263 122
john_ghielec 2:6ab46f2e851a 123 this->checkCollision();
john_ghielec 2:6ab46f2e851a 124
john_ghielec 2:6ab46f2e851a 125 this->drawPaddle();
john_ghielec 2:6ab46f2e851a 126 this->drawBall();
john_ghielec 2:6ab46f2e851a 127
john_ghielec 2:6ab46f2e851a 128 this->checkPwm();
john_ghielec 2:6ab46f2e851a 129 this->checkLives();
john_ghielec 2:6ab46f2e851a 130
john_ghielec 2:6ab46f2e851a 131 wait_ms(25);
john_ghielec 2:6ab46f2e851a 132 }
john_ghielec 2:6ab46f2e851a 133 else {
john_ghielec 2:6ab46f2e851a 134 double x, y, z;
john_ghielec 2:6ab46f2e851a 135
john_ghielec 2:6ab46f2e851a 136 this->getXYZ(x, y, z);
john_ghielec 2:6ab46f2e851a 137
john_ghielec 2:6ab46f2e851a 138 this->checkGraphReset();
john_ghielec 2:6ab46f2e851a 139 this->drawPoint(0, x);
john_ghielec 2:6ab46f2e851a 140 this->drawPoint(1, y);
john_ghielec 2:6ab46f2e851a 141 this->drawPoint(2, z);
john_ghielec 2:6ab46f2e851a 142 this->graphX++;
john_ghielec 2:6ab46f2e851a 143 }
john_ghielec 1:cd8a3926f263 144 }
john_ghielec 1:cd8a3926f263 145
john_ghielec 2:6ab46f2e851a 146 void Game::checkButtons() {
john_ghielec 2:6ab46f2e851a 147 if (!this->square.read()) {
john_ghielec 2:6ab46f2e851a 148 this->mode = !this->mode;
john_ghielec 2:6ab46f2e851a 149
john_ghielec 2:6ab46f2e851a 150 this->disp.clear();
john_ghielec 2:6ab46f2e851a 151
john_ghielec 2:6ab46f2e851a 152 if (!this->mode) {
john_ghielec 2:6ab46f2e851a 153 this->graphX = 0;
john_ghielec 2:6ab46f2e851a 154
john_ghielec 2:6ab46f2e851a 155 this->drawAxes();
john_ghielec 2:6ab46f2e851a 156 }
john_ghielec 2:6ab46f2e851a 157
john_ghielec 2:6ab46f2e851a 158 this->led1.write(this->mode);
john_ghielec 2:6ab46f2e851a 159 this->led2.write(!this->mode);
john_ghielec 2:6ab46f2e851a 160 }
john_ghielec 2:6ab46f2e851a 161
john_ghielec 2:6ab46f2e851a 162 bool xDir = this->ballSpeedX > 0;
john_ghielec 2:6ab46f2e851a 163 bool yDir = this->ballSpeedY > 0;
john_ghielec 2:6ab46f2e851a 164 bool isUp = !this->up.read();
john_ghielec 2:6ab46f2e851a 165 bool isDown = !this->down.read();
john_ghielec 1:cd8a3926f263 166
john_ghielec 2:6ab46f2e851a 167 if (isUp && isDown) goto end;
john_ghielec 2:6ab46f2e851a 168 if (!isUp && !isDown) goto end;
john_ghielec 2:6ab46f2e851a 169
john_ghielec 2:6ab46f2e851a 170 if (isUp && this->lastUp) goto end;
john_ghielec 2:6ab46f2e851a 171 if (isDown && this->lastDown) goto end;
john_ghielec 2:6ab46f2e851a 172
john_ghielec 2:6ab46f2e851a 173 if (!xDir) this->ballSpeedX *= -1;
john_ghielec 2:6ab46f2e851a 174 if (!yDir) this->ballSpeedY *= -1;
john_ghielec 1:cd8a3926f263 175
john_ghielec 2:6ab46f2e851a 176 if (isUp) {
john_ghielec 2:6ab46f2e851a 177 if (++this->ballSpeedX > 5) this->ballSpeedX = 5;
john_ghielec 2:6ab46f2e851a 178 if (++this->ballSpeedY > 5) this->ballSpeedY = 5;
john_ghielec 2:6ab46f2e851a 179 }
john_ghielec 2:6ab46f2e851a 180 else if (isDown) {
john_ghielec 2:6ab46f2e851a 181 if (--this->ballSpeedX == 0) this->ballSpeedX = 1;
john_ghielec 2:6ab46f2e851a 182 if (--this->ballSpeedY == 0) this->ballSpeedY = 1;
john_ghielec 2:6ab46f2e851a 183 }
john_ghielec 1:cd8a3926f263 184
john_ghielec 2:6ab46f2e851a 185 if (!xDir) this->ballSpeedX *= -1;
john_ghielec 2:6ab46f2e851a 186 if (!yDir) this->ballSpeedY *= -1;
john_ghielec 2:6ab46f2e851a 187
john_ghielec 2:6ab46f2e851a 188 end:
john_ghielec 2:6ab46f2e851a 189 this->lastUp = isUp;
john_ghielec 2:6ab46f2e851a 190 this->lastDown = isDown;
john_ghielec 1:cd8a3926f263 191 }
john_ghielec 1:cd8a3926f263 192
john_ghielec 1:cd8a3926f263 193 void Game::drawString(const char* str, int y) {
john_ghielec 1:cd8a3926f263 194 this->disp.drawString(DisplayN18::WIDTH / 2 - (DisplayN18::CHAR_WIDTH + DisplayN18::CHAR_SPACING) * strlen(str) / 2, y, str, DisplayN18::WHITE, DisplayN18::BLACK);
john_ghielec 1:cd8a3926f263 195 }
john_ghielec 1:cd8a3926f263 196
john_ghielec 1:cd8a3926f263 197 void Game::showSplashScreen() {
john_ghielec 2:6ab46f2e851a 198 this->drawString(Game::SPLASH_1, DisplayN18::HEIGHT / 2 - DisplayN18::CHAR_HEIGHT / 2);
john_ghielec 2:6ab46f2e851a 199 this->drawString(Game::SPLASH_2, DisplayN18::HEIGHT / 2 + DisplayN18::CHAR_HEIGHT / 2);
john_ghielec 1:cd8a3926f263 200
john_ghielec 1:cd8a3926f263 201 while (this->circle.read())
john_ghielec 1:cd8a3926f263 202 wait_ms(1);
john_ghielec 1:cd8a3926f263 203
john_ghielec 1:cd8a3926f263 204 this->disp.clear();
john_ghielec 1:cd8a3926f263 205 }
john_ghielec 1:cd8a3926f263 206
john_ghielec 1:cd8a3926f263 207 void Game::clearPaddle() {
john_ghielec 1:cd8a3926f263 208 this->disp.fillRect(this->paddleX, DisplayN18::HEIGHT - Game::PADDLE_HEIGHT, Game::PADDLE_WIDTH, Game::PADDLE_HEIGHT, DisplayN18::BLACK);
john_ghielec 1:cd8a3926f263 209 }
john_ghielec 1:cd8a3926f263 210
john_ghielec 1:cd8a3926f263 211 void Game::drawPaddle() {
john_ghielec 1:cd8a3926f263 212 this->disp.fillRect(this->paddleX, DisplayN18::HEIGHT - Game::PADDLE_HEIGHT, Game::PADDLE_WIDTH, Game::PADDLE_HEIGHT, DisplayN18::BLUE);
john_ghielec 1:cd8a3926f263 213 }
john_ghielec 1:cd8a3926f263 214
john_ghielec 1:cd8a3926f263 215 void Game::updatePaddle() {
john_ghielec 1:cd8a3926f263 216 if (this->left.read())
john_ghielec 1:cd8a3926f263 217 this->paddleX += Game::PADDLE_SPEED;
john_ghielec 1:cd8a3926f263 218
john_ghielec 1:cd8a3926f263 219 if (this->right.read())
john_ghielec 1:cd8a3926f263 220 this->paddleX -= Game::PADDLE_SPEED;
john_ghielec 1:cd8a3926f263 221 }
john_ghielec 1:cd8a3926f263 222
john_ghielec 1:cd8a3926f263 223 void Game::clearBall() {
john_ghielec 1:cd8a3926f263 224 this->disp.fillRect(this->ballX - Game::BALL_RADIUS, ballY - Game::BALL_RADIUS, Game::BALL_RADIUS * 2, Game::BALL_RADIUS * 2, DisplayN18::BLACK);
john_ghielec 1:cd8a3926f263 225 }
john_ghielec 1:cd8a3926f263 226
john_ghielec 1:cd8a3926f263 227 void Game::drawBall() {
john_ghielec 1:cd8a3926f263 228 this->disp.fillRect(this->ballX - Game::BALL_RADIUS, ballY - Game::BALL_RADIUS, Game::BALL_RADIUS * 2, Game::BALL_RADIUS * 2, DisplayN18::RED);
john_ghielec 1:cd8a3926f263 229 }
john_ghielec 1:cd8a3926f263 230
john_ghielec 1:cd8a3926f263 231 void Game::updateBall() {
john_ghielec 1:cd8a3926f263 232 this->ballX += this->ballSpeedX;
john_ghielec 1:cd8a3926f263 233 this->ballY += this->ballSpeedY;
john_ghielec 1:cd8a3926f263 234 }
john_ghielec 1:cd8a3926f263 235
john_ghielec 1:cd8a3926f263 236 void Game::checkCollision() {
john_ghielec 1:cd8a3926f263 237 if (this->paddleX < 0)
john_ghielec 1:cd8a3926f263 238 this->paddleX = 0;
john_ghielec 1:cd8a3926f263 239
john_ghielec 1:cd8a3926f263 240 if (this->paddleX + Game::PADDLE_WIDTH > DisplayN18::WIDTH)
john_ghielec 1:cd8a3926f263 241 this->paddleX = DisplayN18::WIDTH - Game::PADDLE_WIDTH;
john_ghielec 1:cd8a3926f263 242
john_ghielec 1:cd8a3926f263 243 if ((this->ballX - Game::BALL_RADIUS < 0 && this->ballSpeedX < 0) || (this->ballX + Game::BALL_RADIUS >= DisplayN18::WIDTH && this->ballSpeedX > 0))
john_ghielec 1:cd8a3926f263 244 this->ballSpeedX *= -1;
john_ghielec 1:cd8a3926f263 245
john_ghielec 1:cd8a3926f263 246 if (this->ballY - Game::BALL_RADIUS < 0 && this->ballSpeedY < 0)
john_ghielec 1:cd8a3926f263 247 this->ballSpeedY *= -1;
john_ghielec 1:cd8a3926f263 248
john_ghielec 1:cd8a3926f263 249 if (this->ballY + Game::BALL_RADIUS >= DisplayN18::HEIGHT - Game::PADDLE_HEIGHT && this->ballSpeedY > 0) {
john_ghielec 1:cd8a3926f263 250 if (this->ballY + Game::BALL_RADIUS >= DisplayN18::HEIGHT) {
john_ghielec 1:cd8a3926f263 251 this->initializeBall();
john_ghielec 1:cd8a3926f263 252
john_ghielec 1:cd8a3926f263 253 this->lives--;
john_ghielec 1:cd8a3926f263 254 }
john_ghielec 1:cd8a3926f263 255 else if (this->ballX > this->paddleX && this->ballX < this->paddleX + Game::PADDLE_WIDTH) {
john_ghielec 1:cd8a3926f263 256 this->ballSpeedY *= -1;
john_ghielec 1:cd8a3926f263 257
john_ghielec 1:cd8a3926f263 258 this->pwmTicksLeft = Game::BOUNCE_SOUND_TICKS;
john_ghielec 1:cd8a3926f263 259 }
john_ghielec 1:cd8a3926f263 260 }
john_ghielec 1:cd8a3926f263 261 }
john_ghielec 1:cd8a3926f263 262
john_ghielec 1:cd8a3926f263 263 void Game::checkPwm() {
john_ghielec 1:cd8a3926f263 264 if (this->pwmTicksLeft == 0) {
john_ghielec 1:cd8a3926f263 265 this->pwm.write(0.0);
john_ghielec 1:cd8a3926f263 266 }
john_ghielec 1:cd8a3926f263 267 else {
john_ghielec 1:cd8a3926f263 268 this->pwmTicksLeft--;
john_ghielec 1:cd8a3926f263 269 this->pwm.write(0.5);
john_ghielec 1:cd8a3926f263 270 }
john_ghielec 1:cd8a3926f263 271 }
john_ghielec 1:cd8a3926f263 272
john_ghielec 1:cd8a3926f263 273 void Game::checkLives() {
john_ghielec 1:cd8a3926f263 274 if (this->lives == 0) {
john_ghielec 1:cd8a3926f263 275 this->disp.clear();
john_ghielec 1:cd8a3926f263 276
john_ghielec 1:cd8a3926f263 277 this->drawString(Game::LOSE_1, DisplayN18::HEIGHT / 2 - DisplayN18::CHAR_HEIGHT);
john_ghielec 1:cd8a3926f263 278 this->drawString(Game::LOSE_2, DisplayN18::HEIGHT / 2);
john_ghielec 1:cd8a3926f263 279
john_ghielec 1:cd8a3926f263 280 while (this->circle.read())
john_ghielec 1:cd8a3926f263 281 wait_ms(1);
john_ghielec 1:cd8a3926f263 282
john_ghielec 1:cd8a3926f263 283 this->initialize();
john_ghielec 1:cd8a3926f263 284 }
john_ghielec 1:cd8a3926f263 285 else {
john_ghielec 1:cd8a3926f263 286 this->disp.drawCharacter(0, 0, static_cast<char>(this->lives + '0'), DisplayN18::WHITE, DisplayN18::BLACK);
john_ghielec 1:cd8a3926f263 287 }
john_ghielec 1:cd8a3926f263 288 }