A Pong implementation for the UMass CICS 290M Makerboard
// 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