#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <vector>
#include <stdlib.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define PADDLE_WIDTH 20
#define PADDLE_HEIGHT 3
#define BALL_SIZE 5
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
int paddle_x = (SCREEN_WIDTH - PADDLE_WIDTH) / 2;
const int paddle_y = SCREEN_HEIGHT - 5;
int ball_x, ball_y;
int ball_dx, ball_dy;
std::vector<int> bricks_x, bricks_y;
int brick_width = 16;
int brick_height = 4;
int num_bricks = 5; // initial number of bricks
const int min_bricks = 3;
const int max_bricks = 21;
int count = 0;
bool cheat_mode = false;
bool game_running = false;
int button1 = 2; // Move paddle left
int button2 = 17; // Move paddle right and start game
int buzzer = 4; // Buzzer pin
int frequencies[] = {500, 400, 300, 200, 100};
void setup() {
pinMode(button1, INPUT_PULLUP);
pinMode(button2, INPUT_PULLUP);
pinMode(buzzer, OUTPUT);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.display();
srand(millis()); // Initialize random seed
showMenu();
}
void loop() {
if (!game_running) {
handleMenuInput();
} else {
playGame();
}
}
void showMenu() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 10);
display.print("Bricks: ");
if (cheat_mode == true) {
display.setCursor(10, 20);
display.print("Cheats ON");
}
display.setCursor(53, 10);
display.print(num_bricks);
display.setCursor(10, 30);
display.print("Btn1: Change bricks");
display.setCursor(10, 40);
display.print("Btn2: Start game");
display.display();
}
void handleMenuInput() {
if (digitalRead(button1) == LOW) {
delay(200);
num_bricks++;
if (num_bricks > max_bricks) {
num_bricks = min_bricks;
count++;
}
if (count == 2) {
cheat_mode = true;
}
//playTone(300, 100);
showMenu();
}
if (digitalRead(button2) == LOW) {
delay(200);
startGame();
}
}
void startGame() {
game_running = true;
playTone(500, 200);
paddle_x = (SCREEN_WIDTH - PADDLE_WIDTH) / 2;
ball_x = SCREEN_WIDTH / 2;
ball_y = paddle_y - BALL_SIZE;
ball_dx = (rand() % 2 == 0) ? 3 : -3; // Stabilized speed
ball_dy = -3; // Stabilized speed
bricks_x.clear();
bricks_y.clear();
for (int i = 0; i < num_bricks; i++) {
bricks_x.push_back((i % 7) * (brick_width + 2)); // Maximum 7 bricks per row
bricks_y.push_back((i / 7) * (brick_height + 2));
}
display.clearDisplay();
}
void playGame() {
display.clearDisplay();
// Draw paddle
if (!cheat_mode) {
if (digitalRead(button1) == LOW) {
if (paddle_x > 0) paddle_x -= 5;
}
if (digitalRead(button2) == LOW) {
if (paddle_x < SCREEN_WIDTH - PADDLE_WIDTH) paddle_x += 5;
}
} else {
// In cheat mode, automatically follow the ball
paddle_x = ball_x - PADDLE_WIDTH / 2;
if (paddle_x < 0) paddle_x = 0;
if (paddle_x > SCREEN_WIDTH - PADDLE_WIDTH) paddle_x = SCREEN_WIDTH - PADDLE_WIDTH;
}
display.fillRect(paddle_x, paddle_y, PADDLE_WIDTH, PADDLE_HEIGHT, SSD1306_WHITE);
// Move ball
ball_x += ball_dx;
ball_y += ball_dy;
// Bounce off walls
if (ball_x <= 0 || ball_x >= SCREEN_WIDTH - BALL_SIZE) ball_dx *= -1;
if (ball_y <= 0) ball_dy *= -1;
// Bounce off paddle
if (ball_y + BALL_SIZE >= paddle_y && ball_y + BALL_SIZE <= paddle_y + PADDLE_HEIGHT &&
ball_x + BALL_SIZE >= paddle_x && ball_x <= paddle_x + PADDLE_WIDTH) {
ball_dy = -abs(ball_dy); // Ensure the ball always bounces upwards
}
// Check game over
if (ball_y >= SCREEN_HEIGHT) {
game_running = false;
cheat_mode = false;
count = 0;
for (int i = 0; i < 5; i++) {
playTone(frequencies[i], 200);
}
display.clearDisplay();
display.setTextSize(2);
display.setCursor(10, 20);
display.print("Game Over");
display.display();
delay(3000);
showMenu();
return;
}
// Draw ball
display.fillRect(ball_x, ball_y, BALL_SIZE, BALL_SIZE, SSD1306_WHITE);
// Check collision with bricks
for (int i = 0; i < bricks_x.size(); i++) {
if (ball_x + BALL_SIZE > bricks_x[i] && ball_x < bricks_x[i] + brick_width &&
ball_y + BALL_SIZE > bricks_y[i] && ball_y < bricks_y[i] + brick_height) {
ball_dy *= -1;
playTone(700, 100);
bricks_x.erase(bricks_x.begin() + i);
bricks_y.erase(bricks_y.begin() + i);
break;
}
}
// Draw bricks
for (int i = 0; i < bricks_x.size(); i++) {
display.fillRect(bricks_x[i], bricks_y[i], brick_width, brick_height, SSD1306_WHITE);
}
// Check win condition
if (bricks_x.empty()) {
game_running = false;
cheat_mode = false;
count = 0;
for (int i = 5; i > 0; i--) {
playTone(frequencies[i], 200);
}
display.clearDisplay();
display.setTextSize(2);
display.setCursor(20, 20);
display.print("You Win!");
display.display();
delay(3000);
showMenu();
return;
}
display.display();
}
void playTone(int frequency, int duration) {
tone(buzzer, frequency, duration);
delay(duration);
noTone(buzzer);
}