#include <SPI.h>
#include <Wire.h>
 
#include <Adafruit_SSD1306.h>
 
#define OLED_WIDTH 128
#define OLED_HEIGHT 64
 
#define LED 10
 
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_WIDTH, OLED_HEIGHT);
 
const char LEFT_BUTTON_PIN = 2;
const char RIGHT_BUTTON_PIN = 4;
const char START_BUTTON_PIN = 6;
 
int Buzzer = 8;
 
bool hasStarted = false;
bool Pressed = false;
 
int player_y = 110;
int player_x = 27;
int player_width = 12;
 
int Ball_Pos_Y = 50;
int Ball_Pos_X = 30;
 
int Ball_Dir_Y = 1;
int Ball_Dir_X = 1;
 
int Lives = 3;
 
void setup() {
  pinMode(2, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);
 
  pinMode(LED, OUTPUT);
 
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x32)
 
  display.clearDisplay();
 
  display.display();
 
  Draw_TitleScreen();
}
 
void loop() {
 
  digitalWrite(LED, HIGH);
 
  bool Current_Left_State = digitalRead(LEFT_BUTTON_PIN);
  bool Current_Right_State = digitalRead(RIGHT_BUTTON_PIN);
  bool Current_Start_State = digitalRead(START_BUTTON_PIN);
 
  if (Current_Start_State == Pressed && hasStarted == false) {
    display.clearDisplay();
    hasStarted = true;
    display.drawFastHLine(player_x, player_y, player_width, WHITE);
  }
 
  if (hasStarted) {
    Draw_Court();
    Draw_Lives();
  }
 
  if (Current_Left_State == Pressed && hasStarted == true && player_x != 5) {
    player_x -= 2;
    // Draw player moving left. //
    display.drawFastHLine(player_x, player_y, player_width, WHITE);
    display.drawFastHLine(player_x + player_width, player_y, player_width, BLACK);
  }
 
  if (Current_Right_State == Pressed && hasStarted == true && player_x != 47) {
    player_x += 2;
    // Draw player moving right. //
    display.drawFastHLine(player_x, player_y, player_width, WHITE);
    display.drawFastHLine(player_x - player_width, player_y, player_width, BLACK);
  }
 
  display.drawPixel(Ball_Pos_X, Ball_Pos_Y, WHITE);
 
  Draw_Lives();
 
  Ball_Pos_Y += Ball_Dir_Y * 4;
  Ball_Pos_X += Ball_Dir_X * 4;
 
  display.drawPixel(Ball_Pos_X, Ball_Pos_Y, WHITE);
  display.drawPixel(Ball_Pos_X - Ball_Dir_X * 4, Ball_Pos_Y - Ball_Dir_Y * 4, BLACK);
 
  // checks if the ball has hit a vertical wall, and inverts the movement direction.
  if ( Ball_Pos_X <= 1 || Ball_Pos_X >= 63 ) {
    Ball_Dir_X = Ball_Dir_X * -1;
    Sound_Bounce();
  }
  // checks if the ball has hit the ceiling or the player paddle, and inverts the movement direction.
  if ( Ball_Pos_Y <= 16 || Ball_Pos_Y >= 127) {
    Ball_Dir_Y = Ball_Dir_Y * -1;
    Sound_Bounce();
  }
 
  if ( Ball_Pos_Y == 110 && Ball_Pos_X >= player_x && Ball_Pos_X <= player_x + player_width && hasStarted == true) {
    Ball_Dir_Y = Ball_Dir_Y * -1;
    Lives -= 1;
    Sound_Hit();
  }
 
  if (Lives == -1) {
    Game_Over();
  }
 
  display.display();
}
 
void Draw_TitleScreen() {
  // rotate display 90 degrees to match physical orientation. //
  display.setRotation(1);
  // top bar
  display.fillRect(0, 0, 64, 14, WHITE);
  // outline
  display.drawRect(0, 0, 64, 128, WHITE);
 
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(4, 20);
  display.println("ANTI");
  display.setCursor(4, 40);
  display.println("PONG");
 
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(18, 100);
  display.println("Press");
  display.setCursor(18, 108);
  display.println("Start");
 
  tone(Buzzer, 200);
  delay(500);
  noTone(Buzzer);
 
}
 
void Draw_Court() {
  // top bar
  display.fillRect(0, 0, 64, 14, WHITE);
  // outline
  display.drawRect(0, 0, 64, 128, WHITE);
 
  //  display.setTextSize(2);
  //  display.setTextColor(WHITE);
  //  display.setCursor(4, 20);
  //  display.println("Dodge");
  //  display.setCursor(4, 40);
  //  display.println("That");
  //  display.setCursor(4, 60);
  //  display.println("Ball");
}
 
void Sound_Bounce()
{
  if (hasStarted == true) {
    tone(Buzzer, 500, 50);
  }
}
 
void Sound_Hit()
{
  if (hasStarted) {
    tone(Buzzer, 800, 50);
  }
}
 
void Draw_Lives() {
  display.setTextSize(1);
  display.setTextColor(BLACK);
 
  display.setCursor(3, 5);
  display.println("Lives:");
 
  display.setCursor(45, 5);
  display.println(Lives);
 
}
 
void Game_Over() {
  display.clearDisplay();
 
  display.drawRect(0, 0, 64, 128, WHITE);
 
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(4, 10);
  display.println("You");
  display.setCursor(4, 30);
  display.println("Lost");
 
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(4, 100);
  display.println("Back to");
  display.setCursor(4, 108);
  display.println("Menu....");
 
  display.display();
 
  display.drawRect(0, 0, 64, 128, WHITE);
 
  delay(3000);
 
  display.clearDisplay();
 
  Draw_TitleScreen();
  hasStarted = false;
  Lives = 3;
}