/*
Pong is a two-dimensional sports game that simulates table tennis.
by Anderson Costa with ❤ for the Wokwi community
Visit https://wokwi.com to learn about the Wokwi Simulator
*/
#include <TVout.h>
#include <TVoutfonts/fontALL.h>
#include "logo.h"
#define PLAYER1_INPUT A0 // Player 1 control input
#define PLAYER2_INPUT A1 // Player 2 control input
#define SCREEN_WIDTH 128 // Maximum width
#define SCREEN_HEIGHT 96 // Maximum height
#define BALL_TOP_LIMIT 8 // Upper ball collision limit
#define BALL_INF_LIMIT 90 // Lower ball collision limit
#define TOTAL_POINTS 5 // Maximum number of points
TVout TV;
// Player scores
int pointsPlayer1 = 0;
int pointsPlayer2 = 0;
// Set speeds
int speedGame = 10;
int speedBallX = 1;
int speedBallY = -1;
boolean startGame = false;
boolean ownerBall = true;
// Player coordinates
int posPlayer1X = 25;
int posPlayer1Y;
int posPlayer2X = 123;
int posPlayer2Y;
int dirPlayer1;
int dirPlayer2;
// Ball coordinates
int posBallX = 27;
int posBallY;
void setup() {
TV.begin(_PAL, SCREEN_WIDTH, SCREEN_HEIGHT);
posPlayers(); // Updates players position
dirPlayer1 = posPlayer1Y;
dirPlayer2 = posPlayer2Y;
posBallY = posPlayer1Y;
TV.clear_screen();
// Draw border
TV.draw_rect(22, 0, TV.hres() - 23, TV.vres() - 1, 1);
TV.draw_rect(24, 2, TV.hres() - 27, TV.vres() - 5, 1);
// Draw logo
TV.bitmap((TV.hres() - pong_logo[0]) / 2 + 11, (TV.vres() - pong_logo[1]) / 2, pong_logo);
delay(1000);
}
void loop() {
drawScene();
checkMotionPlayers();
movesBall();
delay(speedGame);
if (pointsPlayer1 == TOTAL_POINTS) {
gameOver(1);
}
if (pointsPlayer2 == TOTAL_POINTS) {
gameOver(2);
}
}
void drawScene()
{
// Draw the position of the players
TV.clear_screen();
TV.select_font(font6x8);
TV.print(64, 0, pointsPlayer1);
TV.print(80, 0, pointsPlayer2);
TV.select_font(font4x6);
// Draw rectangular square
TV.draw_rect(22, 8, SCREEN_WIDTH - 23, SCREEN_HEIGHT - 12, WHITE);
// Draw the center column of the court
for (int i = 9; i < 90; i = i + 5) {
TV.draw_column((SCREEN_WIDTH / 2) + 10, i, i + 2, WHITE);
}
// Draw player 1
TV.draw_column(posPlayer1X, (posPlayer1Y - 7), (posPlayer1Y + 7), WHITE);
// Draw player 2
TV.draw_column(posPlayer2X, (posPlayer2Y - 7), (posPlayer2Y + 7), WHITE);
// Draw ball
TV.set_pixel(posBallX, posBallY, WHITE);
}
void posPlayers()
{
posPlayer1Y = map(analogRead(PLAYER1_INPUT), 0, 1023, 16, 83);
posPlayer2Y = map(analogRead(PLAYER2_INPUT), 0, 1023, 16, 83);
}
void checkMotionPlayers()
{
posPlayers(); // Updates players position
if (dirPlayer1 < posPlayer1Y) {
if (!startGame && ownerBall) {
speedBallY = 1;
startGame = true;
}
} else if (dirPlayer1 > posPlayer1Y) {
if (!startGame && ownerBall) {
speedBallY = -1;
startGame = true;
}
}
if (dirPlayer2 < posPlayer2Y) {
if (!startGame && !ownerBall) {
speedBallY = 1;
startGame = true;
}
} else if (dirPlayer2 > posPlayer2Y) {
if (!startGame && !ownerBall) {
speedBallY = -1;
startGame = true;
}
}
dirPlayer1 = posPlayer1Y;
dirPlayer2 = posPlayer2Y;
}
void movesBall()
{
int ballX = posBallX;
int ballY = posBallY;
if (startGame) {
ballX = posBallX + speedBallX;
ballY = posBallY + speedBallY;
}
// Check for top and bottom collisions of the ball with the court
if (ballY == BALL_TOP_LIMIT) {
speedBallY = 1;
soundGame(440, 20); // Sound when the ball hits the top
}
else if (ballY == BALL_INF_LIMIT) {
speedBallY = -1;
soundGame(440, 20); // Sound when the ball hits the bottom
}
// Check for ball collisions with players
// Player 1
if (ballX == 26) {
if (posBallY < posPlayer1Y + 8 && posBallY > posPlayer1Y - 8) {
speedBallX = 1;
if (startGame) {
soundGame(220, 20); // Sound when player 1 hits the ball
}
}
} else if (ballX == 21) {
startGame = false;
ownerBall = false;
ballX = 122;
ballY = posPlayer2Y;
pointsPlayer2++;
soundGame(100, 300); // Sound when player 2 scores
}
// Player 2
if (ballX == 122) {
if (posBallY < posPlayer2Y + 8 && posBallY > posPlayer2Y - 8) {
speedBallX = -1;
if (startGame) {
soundGame(220, 20); // Sound when player 2 hits the ball
}
}
} else if (ballX == SCREEN_WIDTH - 1) {
startGame = false;
ownerBall = true;
ballX = 26;
ballY = posPlayer1Y;
pointsPlayer1++;
soundGame(100, 300); // Sound when player 1 scores
}
posBallX = ballX;
posBallY = ballY;
}
void soundGame(int frequency, int duration)
{
TV.tone(frequency, duration);
}
void gameOver(byte winner)
{
startGame = false;
// Reset points
pointsPlayer1 = 0;
pointsPlayer2 = 0;
TV.clear_screen();
TV.select_font(font8x8);
TV.println(54, 32, "WINNER");
if (winner == 1) {
ownerBall = true;
TV.println(47, 50, "PLAYER 1");
} else {
ownerBall = false;
TV.println(47, 50, "PLAYER 2");
}
// Sound when player 1 or player 2 wins the game
soundGame(520, 500);
delay(5000);
}