#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);
const int JOYSTICK_X_PIN = A0; // X-axis connected to analog pin A0
const int JOYSTICK_Y_PIN = A1; // Y-axis connected to analog pin A1 (not used for paddle control)
const int JOYSTICK_SW_PIN = 2; // Button connected to digital pin 2 (optional)
const int BUZZER_PIN = 3; // Buzzer connected to digital pin 3
int paddleX;
const int paddleWidth = 20;
const int paddleHeight = 4;
const int paddleY = SCREEN_HEIGHT - 10;
int ballX, ballY;
int ballDX = 1;
int ballDY = -1;
const int ballSize = 3;
const int brickRows = 3;
const int brickCols = 8;
const int brickWidth = 14;
const int brickHeight = 5;
const int brickStartY = 10; // Start bricks below the scoreboard
bool bricks[brickRows][brickCols];
int score = 0; // Initialize score
int lives = 3; // Initialize lives
void setup() {
Serial.begin(9600);
pinMode(JOYSTICK_X_PIN, INPUT);
pinMode(JOYSTICK_Y_PIN, INPUT);
pinMode(JOYSTICK_SW_PIN, INPUT_PULLUP); // Configure button pin as input with internal pull-up resistor
pinMode(BUZZER_PIN, OUTPUT); // Configure buzzer pin as output
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x64
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Don't proceed, loop forever
}
display.display();
delay(2000); // Pause for 2 seconds
display.clearDisplay();
paddleX = (SCREEN_WIDTH - paddleWidth) / 2;
ballX = SCREEN_WIDTH / 2;
ballY = SCREEN_HEIGHT / 2;
// Initialize bricks array
for (int i = 0; i < brickRows; i++) {
for (int j = 0; j < brickCols; j++) {
bricks[i][j] = true; // All bricks start as active
}
}
}
void loop() {
// Read joystick input
int joystickX = analogRead(JOYSTICK_X_PIN);
// Map joystick input to paddle position
paddleX = map(joystickX, 0, 1023, 0, SCREEN_WIDTH - paddleWidth);
// Move the ball
ballX += ballDX;
ballY += ballDY;
// Ball collision with walls
if (ballX <= 0 || ballX >= SCREEN_WIDTH - ballSize) {
ballDX = -ballDX;
}
if (ballY <= 0) {
ballDY = -ballDY;
}
// Ball collision with paddle
if (ballY >= paddleY - ballSize && ballX + ballSize >= paddleX && ballX <= paddleX + paddleWidth) {
ballDY = -ballDY;
}
// Ball out of bounds (lose condition)
if (ballY > SCREEN_HEIGHT) {
ballX = SCREEN_WIDTH / 2;
ballY = SCREEN_HEIGHT / 2;
ballDX = 1;
ballDY = -1;
lives--; // Decrease lives by 1
tone(BUZZER_PIN, 1500, 200); // Play losing life sound
if (lives == 0) {
// Display "You lose" message
display.clearDisplay();
display.setTextSize(2); // Large text size
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(10, 20); // Centered position
display.print(F("You Lose"));
display.display();
delay(3000); // Pause for 3 seconds
noTone(BUZZER_PIN); // Turn off buzzer
// Reset game
lives = 3;
score = 0;
// Reinitialize bricks
for (int i = 0; i < brickRows; i++) {
for (int j = 0; j < brickCols; j++) {
bricks[i][j] = true;
}
}
}
}
// Ball collision with bricks
for (int i = 0; i < brickRows; i++) {
for (int j = 0; j < brickCols; j++) {
if (bricks[i][j]) {
int brickX = j * (brickWidth + 2);
int brickY = brickStartY + i * (brickHeight + 2); // Adjust brick Y position to start below scoreboard
if (ballX + ballSize > brickX && ballX < brickX + brickWidth && ballY + ballSize > brickY && ballY < brickY + brickHeight) {
ballDY = -ballDY;
bricks[i][j] = false; // Remove the brick
score += 10; // Increase score by 10
}
}
}
}
// Clear display
display.clearDisplay();
// Draw paddle
display.fillRect(paddleX, paddleY, paddleWidth, paddleHeight, SSD1306_WHITE);
// Draw ball
display.fillRect(ballX, ballY, ballSize, ballSize, SSD1306_WHITE);
// Draw bricks
for (int i = 0; i < brickRows; i++) {
for (int j = 0; j < brickCols; j++) {
if (bricks[i][j]) {
int brickX = j * (brickWidth + 2);
int brickY = brickStartY + i * (brickHeight + 2);
display.fillRect(brickX, brickY, brickWidth, brickHeight, SSD1306_WHITE);
}
}
}
// Display the score
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.print(F("Score: "));
display.print(score);
// Display the lives
display.setCursor(70, 0); // Set cursor position for lives display
display.print(F("Lives: "));
display.print(lives);
// Update display
display.display();
// Delay to control game speed
delay(20);
}