#include <SPI.h>
#include <Wire.h> // This library allows you to communicate with I2C
#include <Adafruit_GFX.h> // Adafruit GFX graphics core library
#include <Adafruit_SSD1306.h> // Driver library for 'monochrome' 128x64 and 128x32 OLEDs
// Define the PINS you're goint to use on your Arduino Nano
int controller1 = 2; // ANALOG 2
int controller2 = 15; // ANALOG 3
int ledPin = 4; // DIGITAL 4
int btnPin = 5; // DIGITAL 5
// Define variables
int buttonState = 0; // HIGH = Pressed
int gameState = 0; // 0 = Home, 1 = Game, 2 = End
int controllerValue1 = 0; // variable to store the value coming from the potentiometer
int controllerValue2 = 0; // variable to store the value coming from the potentiometer
int paddlePositionPlayer1 = 0;
int paddlePositionPlayer2 = 0;
int scorePlayer1 = 0;
int scorePlayer2 = 0;
int ballX = 128 / 2;
int ballY = 64 / 2;
//en el original sin cambio de veocidad era "int"
float ballSpeedX = 2;
float ballSpeedY = 1;
// Cuentagolpes para saber cuándo cambiar de velocidad.
int cuentagolpes = 0;
int cambiovelocidad = 4; //Numero de golpes para cambiar velocidad.
int level = 0; //Nivel de velocidad de la pelota
int ballsize = 2;
#define OLED_RESET 4
// Variables de almacenamiento de la posición de la bola para dibujar una estela.
int Xold1 = 0;
int Yold1 = 0;
int Xold2 = 0;
int Yold2 = 0;
int Xold3 = 0;
int Yold3 = 0;
int Xold4 = 0;
int Yold4 = 0;
int Xold5 = 0;
int Yold5 = 0;
int primer_bucle = 0;
//Buzzer pin.
const int pinBuzzer = 9;
int freq = 440;
//bAdafruit_SSD1306 display(OLED_RESET);
// La línea de arriba la he cambiado porque si no no inicializaba bien la pantalla.
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);
#if (SSD1306_LCDHEIGHT != 64)
#endif
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(btnPin, INPUT);
Serial.begin(9600);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x64)
display.clearDisplay();
digitalWrite(ledPin, HIGH); // Status led on...
}
void loop() {
// Read controller value and calculate paddle position
controllerValue1 = analogRead(controller1);
controllerValue2 = analogRead(controller2);
paddlePositionPlayer1 = controllerValue1 * (46.0 / 1023.0);
paddlePositionPlayer2 = controllerValue2 * (46.0 / 1023.0);
// Set button state
buttonState = digitalRead(btnPin);
// Gamestate = 0: juego sin empezar, 1 juego empezado, 2 juego finalizado.
if (buttonState == HIGH && gameState == 0) {
gameState = 1;
freq = 440;
tone(pinBuzzer, 200, 100);
delay(300); // Hago un debounce sencillito.
countdown(); //Cuenta atrás;
} else if (buttonState == HIGH && (gameState == 1 || gameState == 2)) {
tone(pinBuzzer, 200, 100);
gameState = 0;
scorePlayer1 = 0;
scorePlayer2 = 0;
ballX = 128 / 2 + random(0, 5);
ballY = 64 / 2 + random(0, 5);
level = 0;
//Reseteo la velocidad ee la bola.
ballSpeedX = 2;
ballSpeedY = 1;
primer_bucle = 0;
delay(250);
}
// Pantalla de inicio.
if (gameState == 0) {
display.drawRoundRect(2, 2, 124, 60, 8, WHITE);
display.drawRoundRect(4, 4, 120, 56, 8, WHITE);
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(40, 18);
display.println("PONG");
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(32, 38);
display.println("PULSA START");
display.display();
display.clearDisplay();
}
if (gameState == 1) {
// JUEGO EN MARCHA
drawField(scorePlayer1, scorePlayer2);
collisionControl();
drawBall(); //dibujamos la bola en las ccordenadas que nos mandan.
rapido(); //Cambio velocidad si hay un numero de golpes determinado.
display.display();
display.clearDisplay();
// FIN JUEGO EN MARCHA
}
if (gameState == 2) {
drawField(scorePlayer1, scorePlayer2);
display.setTextSize(1);
display.setTextColor(WHITE);
if (scorePlayer1 == 2) {
display.setCursor(15, 30);
} else if (scorePlayer2 == 2) {
display.setCursor(77, 30);
}
display.println("GANADOR");
display.display();
display.clearDisplay();
}
}
void drawField(int score1, int score2) {
display.fillRect(0, round(paddlePositionPlayer1), 2, 18, 1);
display.fillRect(126, round(paddlePositionPlayer2), 2, 18, 1);
//Muestro level
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(4, 0);
display.print("L");
display.print(":");
display.print(level);
//Muestro marcador
display.setCursor(55, 0);
display.print(score1);
display.print(":");
display.print(score2);
// Separador del campo.
display.fillRect(63, 12, 1, 5, 1);
display.fillRect(63, 22, 1, 5, 1);
display.fillRect(63, 32, 1, 5, 1);
display.fillRect(63, 42, 1, 5, 1);
display.fillRect(63, 52, 1, 5, 1);
display.fillRect(63, 62, 1, 5, 1);
}
void collisionControl() {
//bounce from top and bottom
if (ballY >= 64 - 2 || ballY <= 0) {
ballSpeedY *= -1;
}
//bounce from player1
if (ballX >= 0 && ballX <= 8 && ballSpeedX < 0) {
if (ballY > round(paddlePositionPlayer1) - 2 && ballY < round(paddlePositionPlayer1) + 18) {
ballSpeedX *= -1;
cuentagolpes++;
rebote(freq);
ballSpeedY = ballSpeedY + random(-ballSpeedY / 6, ballSpeedY / 6); //Cambio el ángulo de rebote un poco
}
}
//bounce from player2
if (ballX >= 128 - 2 - 6 && ballX <= 128 - 2 && ballSpeedX > 0) {
if (ballY > round(paddlePositionPlayer2) - 2 && ballY < round(paddlePositionPlayer2) + 18) {
ballSpeedX *= -1;
cuentagolpes++;
rebote(freq);
ballSpeedY = ballSpeedY + random(-ballSpeedY / 6, ballSpeedY / 6); //Cambio el ángulo de rebote un poco
}
}
//score points if ball hits wall behind player
if (ballX >= 128 - 2 || ballX <= 0) {
if (ballSpeedX > 0) {
scorePlayer1++;
gol(); // Goal tone
delay(1000);
ballX = (128 / 4) + random(-3, 3); //Small random position variation
}
if (ballSpeedX < 0) {
scorePlayer2++;
gol(); // Goal tone
delay(1000);
ballX = 128 / 4 * 3 + random(-3, 3); //Small random position variation
}
if (scorePlayer1 == 2 || scorePlayer2 == 2) {
gameState = 2;
gol(); // end tone
gol();
}
}
}
void drawBall() {
// display.fillRect(ballX, ballY, 2, 2, 1); // Bola pequeña
// Algunos condicionales para cambiar el tamaño de la bola.
if (ballX < 10 || ballX > 116) {
ballsize = 1;
}
if ((ballX < 32 && ballX >= 10) || (ballX > 96 && ballX <= 116)) {
ballsize = 2;
}
if ((ballX >= 32 && ballX < 54) || (ballX > 74 && ballX <= 96)) {
ballsize = 3;
}
if (ballX > 54 && ballX <= 74) {
ballsize = 4;
}
if (level < 4)
{
//Dibujo la bola.
display.fillCircle(ballX, ballY, ballsize, WHITE);
ballX += ballSpeedX;
ballY += ballSpeedY;
Serial.print("Posición de la bola (X-Y): ");
Serial.print(ballX);
Serial.print(" - ");
Serial.println(ballY);
}
else
//Nivel 4, efectos molones a la bola.
{
if (primer_bucle == 0)
{
Xold1 = ballX;
Yold1 = ballY;
Xold2 = ballX;
Yold2 = ballY;
Xold3 = ballX;
Yold3 = ballY;
Xold4 = ballX;
Yold4 = ballY;
Xold5 = ballX;
Yold5 = ballY;
primer_bucle = 1;
}
else if (primer_bucle == 1)
//Dibujo las bolas
{
display.fillCircle(ballX, ballY, ballsize, WHITE);
display.drawCircle(Xold1, Yold1, ballsize, WHITE);
display.drawCircle(Xold2, Yold2, ballsize, WHITE);
display.drawCircle(Xold3, Yold3, ballsize, WHITE);
display.drawCircle(Xold4, Yold4, ballsize, WHITE);
display.drawCircle(Xold5, Yold5, ballsize, WHITE);
ballX += ballSpeedX;
ballY += ballSpeedY;
Xold5 = Xold4;
Yold5 = Yold4;
Xold4 = Xold3;
Yold4 = Yold3;
Xold3 = Xold2;
Yold3 = Yold2;
Xold2 = Xold1;
Yold2 = Yold1;
Xold1 = ballX;
Yold1 = ballY;
}
}
}
void rapido() {
if (cuentagolpes >= cambiovelocidad) {
if (level == 0) {
//Entro en el nivel 1
cuentagolpes = 0;
Serial.print("Level ");
Serial.println(level);
// Nueva velocidad y dirección.
ballSpeedX = 3;
ballSpeedY = 1;
Serial.println("Cambio de velocidad");
Serial.print("Velocidad X=");
Serial.print(ballSpeedX);
Serial.print(", Y=");
Serial.println(ballSpeedY);
Serial.print("Level ");
Serial.println(level);
level++;
freq = freq + 100;
}
else if (level == 1) {
//Entro en el nivel 2
cuentagolpes = 0;
Serial.print("Level ");
Serial.println(level);
ballSpeedX = 3;
ballSpeedY = 2;
Serial.println("Cambio de velocidad");
Serial.print("Velocidad X=");
Serial.print(ballSpeedX);
Serial.print(", Y=");
Serial.println(ballSpeedY);
level++;
freq = freq + 100;
}
else if (level == 2) {
//Entro en el nivel 3
cuentagolpes = 0;
Serial.print("Level ");
Serial.println(level);
ballSpeedX = 4;
ballSpeedY = 2;
Serial.println("Cambio de velocidad");
Serial.print("Velocidad X=");
Serial.print(ballSpeedX);
Serial.print(", Y=");
Serial.println(ballSpeedY);
level++;
freq = freq + 100;
}
else if (level == 3) {
//Entro en el nivel 4
cuentagolpes = 0;
Serial.print("Level ");
Serial.println(level);
Serial.println("Cambio de velocidad");
Serial.print("Velocidad X=");
Serial.print(ballSpeedX);
Serial.print(", Y=");
Serial.println(ballSpeedY);
freq = freq + 100;
level++;
}
else if (level >= 4) {
//Entro en el nivel 5
cuentagolpes = -1;
if (ballSpeedY == 2)
{
ballSpeedY = 4;
}
else
{
ballSpeedY = 2;
level = 5;
}
freq = 1000;
Serial.print("Level MAX ");
Serial.println(level);
}
}
}
//Cuenta atrás al inicio.
void countdown() {
display.drawRoundRect(2, 2, 124, 60, 8, WHITE);
display.drawRoundRect(4, 4, 120, 56, 8, WHITE);
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(60, 25);
display.println("3");
display.display();
display.clearDisplay();
delay(1000);
display.drawRoundRect(2, 2, 124, 60, 8, WHITE);
display.drawRoundRect(4, 4, 120, 56, 8, WHITE);
display.drawRoundRect(6, 6, 116, 52, 8, WHITE);
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(60, 25);
display.println("2");
display.display();
display.clearDisplay();
delay(1000);
display.drawRoundRect(2, 2, 124, 60, 8, WHITE);
display.drawRoundRect(4, 4, 120, 56, 8, WHITE);
display.drawRoundRect(6, 6, 116, 52, 8, WHITE);
display.drawRoundRect(8, 8, 112, 48, 8, WHITE);
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(60, 25);
display.println("1");
display.display();
display.clearDisplay();
delay(1000);
display.drawRoundRect(2, 2, 124, 60, 8, WHITE);
display.drawRoundRect(4, 4, 120, 56, 8, WHITE);
display.drawRoundRect(6, 6, 116, 52, 8, WHITE);
display.drawRoundRect(8, 8, 112, 48, 8, WHITE);
display.drawRoundRect(10, 10, 108, 52, 8, WHITE);
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(40, 22);
display.println("GO!");
display.display();
display.clearDisplay();
delay(1000);
}
int rebote(int freqx) {
tone(pinBuzzer, freq, 100);
}
void gol() {
tone(pinBuzzer, 300, 1000);
}