A Pong implementation for the UMass CICS 290M Makerboard
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Imports | |
#include <Adafruit_SSD1306.h> | |
// Globals | |
#define UP_BUTTON 34 | |
#define DOWN_BUTTON 0 | |
#define RESET_BUTTON 35 | |
#define BUZZER 17 | |
// Game State | |
int score = 0; | |
// Paddle | |
int paddle_pos = 32; | |
int paddle_velocity = 1; | |
int paddle_height = 16; | |
int paddle_width = 4; | |
// Ball | |
volatile int ball_x = random(10, 80); | |
volatile int ball_y = random(16, 48); | |
volatile int ball_radius = 3; | |
volatile int ball_velocity_x = random(1, 3); | |
volatile int ball_velocity_y = random(1, 3); | |
Adafruit_SSD1306 lcd(128, 64); // create display object | |
// Callbacks | |
void IRAM_ATTR moveUp() { | |
if (paddle_pos >= 0) { | |
paddle_pos -= 1; | |
} | |
} | |
void IRAM_ATTR moveDown() { | |
if (paddle_pos + paddle_height <= 64) { | |
paddle_pos += 1; | |
} | |
} | |
void IRAM_ATTR restart() { | |
if (gameOver()) { | |
score = 0; | |
ball_x = random(10, 80); | |
ball_y = random(16, 48); | |
ball_velocity_x = random(1, 3); | |
ball_velocity_y = random(1, 3); | |
} | |
} | |
void setup() { | |
Serial.begin(9600); | |
pinMode(BUZZER, OUTPUT); | |
pinMode(UP_BUTTON, INPUT); | |
pinMode(DOWN_BUTTON, INPUT); | |
pinMode(RESET_BUTTON, INPUT); | |
lcd.begin(SSD1306_SWITCHCAPVCC, 0x3C); // init | |
lcd.setTextColor(WHITE); | |
lcd.clearDisplay(); // clear software buffer | |
lcd.display(); | |
attachInterrupt(RESET_BUTTON, restart, FALLING); | |
} | |
// Test if coordinates are out of bounds | |
boolean yIsOutOfBounds(int y) {return y > 63 || y < 0;} | |
boolean xIsOutOfBounds(int x) {return x > 127 || x < 0;} | |
boolean outOfBounds(int x, int y) {return xIsOutOfBounds(x) || yIsOutOfBounds(y);} | |
boolean gameOver() {return ball_x + ball_radius >= 127;} | |
boolean ballPaddleCollision(int x, int y) { | |
return (x > 128 - paddle_width) && (y < paddle_pos + paddle_height && y > paddle_pos); | |
} | |
void drawPaddle(int x, int y, int width, int height) { | |
lcd.fillRect(x, y, width, height, WHITE); | |
} | |
void ding() { | |
ledcSetup(0, 5000, 8); | |
ledcAttachPin(BUZZER, 0); | |
ledcWriteTone(0, 500); | |
delay(50); // 500Hz for 0.05 second | |
ledcWriteTone(0, 0); // buzzer off | |
} | |
void drawBall() { | |
lcd.fillCircle(ball_x, ball_y, ball_radius, BLACK); | |
if (xIsOutOfBounds(ball_x + ball_radius) || xIsOutOfBounds(ball_x - ball_radius)) { | |
ball_velocity_x *= -1; | |
ding(); | |
} | |
if (yIsOutOfBounds(ball_y + ball_radius) || yIsOutOfBounds(ball_y - ball_radius)) {ball_velocity_y *= -1;} | |
if (ballPaddleCollision(ball_x + ball_radius, ball_y) || ballPaddleCollision(ball_x - ball_radius, ball_y)) { | |
ball_velocity_x *= -1; | |
ding(); | |
score++; | |
} | |
ball_x += ball_velocity_x; | |
ball_y += ball_velocity_y; | |
lcd.fillCircle(ball_x, ball_y, ball_radius, WHITE); | |
} | |
void loop() { | |
// Check if Game is over | |
if (gameOver()) { | |
lcd.clearDisplay(); | |
lcd.setCursor(0,0); | |
lcd.print("Score: " + String(score) + "\nPress bottom button \nto restart."); | |
lcd.display(); | |
return; | |
} | |
// Check for button presses | |
if (!digitalRead(UP_BUTTON)) { | |
moveUp(); | |
} | |
if (!digitalRead(DOWN_BUTTON)) { | |
moveDown(); | |
} | |
lcd.clearDisplay(); | |
drawPaddle(0, ball_y - (paddle_height / 2), paddle_width, paddle_height); | |
drawPaddle(127 - paddle_width, paddle_pos + paddle_velocity, paddle_width, paddle_height); | |
drawBall(); | |
lcd.display(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment