#include <Arduino.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#define TFT_DC 2 // Define pin for data/command selection
#define TFT_CS 3 // Define pin for chip select
#define SCREEN_WIDTH 320 // Define screen width in pixels
#define SCREEN_HEIGHT 240 // Define screen height in pixels
#define PADDLE_WIDTH 5 // Define width of paddles in pixels
#define PADDLE_HEIGHT 40 // Define height of paddles in pixels
#define BALL_SIZE 5 // Define size of ball in pixels
#define PADDLE_SPEED 8 // Define speed of paddles
#define BALL_SPEED 5 // Define speed of ball
#define BUTTON1 D7 // Define pin for button 1
#define BUTTON2 D6 // Define pin for button 2
#define BUTTON3 D5 // Define pin for button 3
#define BUTTON4 D4 // Define pin for button 4
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); // Create an instance of the Adafruit_ILI9341 library
struct Vector2 { // Define a structure to represent a 2D vector
int x, y;
};
Vector2 paddle1 = {10, SCREEN_HEIGHT / 2 - PADDLE_HEIGHT / 2}; // Initialize position of paddle 1
Vector2 paddle2 = {SCREEN_WIDTH - PADDLE_WIDTH - 10, SCREEN_HEIGHT / 2 - PADDLE_HEIGHT / 2}; // Initialize position of paddle 2
Vector2 ball = {SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2}; // Initialize position of ball
Vector2 ballVelocity = {BALL_SPEED, BALL_SPEED}; // Initialize velocity of ball
int scorePaddle1 = 0; // Initialize score for paddle 1
int scorePaddle2 = 0; // Initialize score for paddle 2
void setup() {
Serial.begin(9600); // Begin serial communication
tft.begin(); // Initialize the ILI9341 display
tft.setRotation(3); // Set display rotation
tft.fillScreen(ILI9341_BLACK); // Clear the screen with black color
pinMode(BUTTON1, INPUT_PULLUP); // Configure button 1 pin as input with pull-up resistor
pinMode(BUTTON2, INPUT_PULLUP); // Configure button 2 pin as input with pull-up resistor
pinMode(BUTTON3, INPUT_PULLUP); // Configure button 3 pin as input with pull-up resistor
pinMode(BUTTON4, INPUT_PULLUP); // Configure button 4 pin as input with pull-up resistor
}
void loop() {
// Store previous positions of paddles
int prevPaddle1Y = paddle1.y;
int prevPaddle2Y = paddle2.y;
// Move paddles based on button inputs
if (digitalRead(BUTTON1)) paddle1.y -= PADDLE_SPEED;
if (digitalRead(BUTTON2)) paddle1.y += PADDLE_SPEED;
if (digitalRead(BUTTON3)) paddle2.y -= PADDLE_SPEED;
if (digitalRead(BUTTON4)) paddle2.y += PADDLE_SPEED;
// Ensure paddles stay within screen bounds
paddle1.y = constrain(paddle1.y, 0, SCREEN_HEIGHT - PADDLE_HEIGHT);
paddle2.y = constrain(paddle2.y, 0, SCREEN_HEIGHT - PADDLE_HEIGHT);
// Clear previous positions of paddles and ball
tft.fillRect(paddle1.x, prevPaddle1Y, PADDLE_WIDTH, PADDLE_HEIGHT, ILI9341_BLACK);
tft.fillRect(paddle2.x, prevPaddle2Y, PADDLE_WIDTH, PADDLE_HEIGHT, ILI9341_BLACK);
tft.fillRect(ball.x, ball.y, BALL_SIZE, BALL_SIZE, ILI9341_BLACK);
// Update ball position
ball.x += ballVelocity.x;
ball.y += ballVelocity.y;
// Handle ball collisions with screen edges and paddles
if (ball.y <= 0 || ball.y >= SCREEN_HEIGHT - BALL_SIZE) ballVelocity.y *= -1;
if (ball.x <= paddle1.x + PADDLE_WIDTH && ball.y >= paddle1.y && ball.y <= paddle1.y + PADDLE_HEIGHT) ballVelocity.x *= -1;
if (ball.x + BALL_SIZE >= paddle2.x && ball.y >= paddle2.y && ball.y <= paddle2.y + PADDLE_HEIGHT) ballVelocity.x *= -1;
// Check if ball goes out of bounds and update scores
if (ball.x <= 0) {
scorePaddle2++; // Increment score for Paddle 2
ball.x = SCREEN_WIDTH / 2; // Reset ball position
} else if (ball.x >= SCREEN_WIDTH - BALL_SIZE) {
scorePaddle1++; // Increment score for Paddle 1
ball.x = SCREEN_WIDTH / 2; // Reset ball position
}
// Ensure ball stays within screen bounds
ball.x = constrain(ball.x, 0, SCREEN_WIDTH - BALL_SIZE);
ball.y = constrain(ball.y, 0, SCREEN_HEIGHT - BALL_SIZE);
// Draw paddles and ball
tft.fillRect(paddle1.x, paddle1.y, PADDLE_WIDTH, PADDLE_HEIGHT, ILI9341_WHITE);
tft.fillRect(paddle2.x, paddle2.y, PADDLE_WIDTH, PADDLE_HEIGHT, ILI9341_WHITE);
tft.fillRect(ball.x, ball.y, BALL_SIZE, BALL_SIZE, ILI9341_WHITE);
// Update and display scores
updateScores();
// Check for winner and reset game if necessary
if (scorePaddle1 >= 5 || scorePaddle2 >= 5) {
announceWinner(); // Announce the winner
delay(5000); // Delay for 5 seconds before resetting the game
resetGame(); // Reset the game
}
delay(10); // ~60 FPS
}
// Function to update and display scores
void updateScores() {
tft.fillRect(50, 0, 50, 20, ILI9341_BLACK); // Clear previous score for Paddle 1
tft.fillRect(SCREEN_WIDTH - 80, 0, 50, 20, ILI9341_BLACK); // Clear previous score for Paddle 2
tft.setCursor(50, 0); // Set cursor position for Paddle 1 score
tft.setTextColor(ILI9341_WHITE); // Set text color to white
tft.setTextSize(2); // Set text size
tft.print(scorePaddle1); // Print Paddle 1 score
tft.setCursor(SCREEN_WIDTH - 80, 0); // Set cursor position for Paddle 2 score
tft.print(scorePaddle2); // Print Paddle 2 score
}
// Function to announce the winner
void announceWinner() {
tft.setCursor(SCREEN_WIDTH / 2 - 50, SCREEN_HEIGHT / 2 - 10); // Set cursor position for winner announcement
tft.setTextColor(ILI9341_WHITE); // Set text color to white
tft.setTextSize(2); // Set text size
if (scorePaddle1 >= 5) {
tft.print("Player 1 wins!"); // Print winner announcement for Player 1
} else {
tft.print("Player 2 wins!"); // Print winner announcement for Player 2
}
}
// Function to reset the game
void resetGame() {
tft.fillScreen(ILI9341_BLACK); // Clear the screen with black color
scorePaddle1 = 0; // Reset score for Paddle 1
scorePaddle2 = 0; // Reset score for Paddle 2
}