#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define JOYSTICK_HORZ 35
#define JOYSTICK_VERT 34
#define JOYSTICK_SEL 32
int playerX = 4;
int playerY = 25;
int botX = 121;
int botY = 25;
int padW = 3;
int padH = 16;
float ballX = 64;
float ballY = 32;
float ballDX = 2;
float ballDY = 1.3;
int playerScore = 0;
int botScore = 0;
bool over = false;
unsigned long lastFrame = 0;
unsigned long lastButton = 0;
void setup() {
Serial.begin(115200);
pinMode(JOYSTICK_SEL, INPUT_PULLUP);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
for (;;);
}
startGame();
}
void loop() {
if (over) {
if (digitalRead(JOYSTICK_SEL) == LOW && millis() - lastButton > 300) {
lastButton = millis();
startGame();
}
return;
}
if (millis() - lastFrame > 24) {
lastFrame = millis();
controlPlayer();
moveBot();
moveBall();
drawGame();
}
}
void startGame() {
playerY = 25;
botY = 25;
playerScore = 0;
botScore = 0;
over = false;
resetBall();
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(49, 18);
display.println("PONG");
display.setCursor(12, 36);
display.println("Move up / down");
display.display();
delay(1000);
}
void controlPlayer() {
int v = analogRead(JOYSTICK_VERT);
if (v > 3000) {
playerY -= 3;
}
if (v < 1000) {
playerY += 3;
}
if (playerY < 8) {
playerY = 8;
}
if (playerY + padH > SCREEN_HEIGHT) {
playerY = SCREEN_HEIGHT - padH;
}
}
void moveBot() {
int botCenter = botY + padH / 2;
if (ballY > botCenter + 2) {
botY += 2;
}
if (ballY < botCenter - 2) {
botY -= 2;
}
if (botY < 8) {
botY = 8;
}
if (botY + padH > SCREEN_HEIGHT) {
botY = SCREEN_HEIGHT - padH;
}
}
void moveBall() {
ballX += ballDX;
ballY += ballDY;
if (ballY <= 8) {
ballY = 8;
ballDY = -ballDY;
}
if (ballY >= SCREEN_HEIGHT - 2) {
ballY = SCREEN_HEIGHT - 2;
ballDY = -ballDY;
}
if (ballX <= playerX + padW && ballX >= playerX) {
if (ballY + 2 >= playerY && ballY <= playerY + padH) {
ballX = playerX + padW + 1;
ballDX = abs(ballDX) + 0.12;
float hit = (ballY - playerY) / padH;
ballDY = (hit - 0.5) * 4;
}
}
if (ballX + 2 >= botX && ballX <= botX + padW) {
if (ballY + 2 >= botY && ballY <= botY + padH) {
ballX = botX - 3;
ballDX = -abs(ballDX) - 0.12;
float hit = (ballY - botY) / padH;
ballDY = (hit - 0.5) * 4;
}
}
if (ballX < 0) {
botScore++;
checkScore();
resetBall();
}
if (ballX > SCREEN_WIDTH) {
playerScore++;
checkScore();
resetBall();
}
}
void checkScore() {
if (playerScore >= 5 || botScore >= 5) {
endGame();
}
}
void resetBall() {
ballX = 64;
ballY = 32;
if (random(0, 2) == 0) {
ballDX = 2;
} else {
ballDX = -2;
}
if (random(0, 2) == 0) {
ballDY = 1.3;
} else {
ballDY = -1.3;
}
delay(400);
}
void drawGame() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(35, 0);
display.print(playerScore);
display.setCursor(88, 0);
display.print(botScore);
display.drawLine(0, 7, SCREEN_WIDTH, 7, SSD1306_WHITE);
for (int y = 10; y < SCREEN_HEIGHT; y += 8) {
display.drawPixel(64, y, SSD1306_WHITE);
display.drawPixel(64, y + 1, SSD1306_WHITE);
}
display.fillRect(playerX, playerY, padW, padH, SSD1306_WHITE);
display.fillRect(botX, botY, padW, padH, SSD1306_WHITE);
display.fillRect((int)ballX, (int)ballY, 2, 2, SSD1306_WHITE);
display.display();
}
void endGame() {
over = true;
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
if (playerScore > botScore) {
display.setCursor(38, 12);
display.println("YOU WIN");
} else {
display.setCursor(34, 12);
display.println("YOU LOSE");
}
display.setCursor(38, 30);
display.print(playerScore);
display.print(" : ");
display.print(botScore);
display.setCursor(6, 50);
display.println("Press joystick");
display.display();
}