14 Commits

Author SHA1 Message Date
andrea
68dfce8b12 Merge branch 'master.use_classes'
Some checks failed
Arduino Pong CI / build (macos-latest) (push) Has been cancelled
Arduino Pong CI / build (ubuntu-latest) (push) Has been cancelled
Arduino Pong CI / build (windows-latest) (push) Has been cancelled
Arduino Pong CD / release (push) Has been cancelled
2026-03-18 21:45:39 +01:00
andrea
49a772f6de clean logs and improve engine handling by removing hits and movment_delay from the loop to the engine 2026-03-18 21:41:51 +01:00
andrea
abc0ddb661 fix collision state 2026-03-18 20:49:25 +01:00
andrea
33e070c442 added renderer.cpp/h files 2026-03-18 20:38:31 +01:00
andrea
1f6e65c5ec renderer class 2026-03-18 19:46:52 +01:00
andrea
7afa70c9d8 fix ball bouncing on pad behavior
now the ball bounces on pad when hit the pad, not when it reaches the edge of the "screen"
2026-03-18 19:12:09 +01:00
andrea
792c0f835c clean main sketch file 2026-03-18 19:00:50 +01:00
andrea
5afa726015 minors 2026-03-18 18:24:52 +01:00
andrea
48fef4be86 move some logics to loop() 2026-03-18 18:12:38 +01:00
andrea
48c2610561 TODO 2026-03-17 23:43:37 +01:00
andrea
3d8881ab3d total reframe with classes 2026-03-17 23:25:30 +01:00
andrea
d8efabd6da start refactoring pong entities to use classes 2026-03-17 20:11:21 +01:00
andrea
c774e11923 Improve arduino_pong.ino using enum to handle game statuses and switch case for better readibility and little memory improvements
Some checks failed
Arduino Pong CI / build (macos-latest) (push) Has been cancelled
Arduino Pong CI / build (ubuntu-latest) (push) Has been cancelled
Arduino Pong CI / build (windows-latest) (push) Has been cancelled
Arduino Pong CD / release (push) Has been cancelled
2026-03-17 18:42:48 +01:00
andrea
b3f6aeb3fe Show scores on the matrix, show winner message once someone reches 9, add start ball movement delay on start and restart after score, and fix uncentered ball on restart
Some checks failed
Arduino Pong CI / build (macos-latest) (push) Has been cancelled
Arduino Pong CI / build (ubuntu-latest) (push) Has been cancelled
Arduino Pong CI / build (windows-latest) (push) Has been cancelled
2026-03-16 22:37:53 +01:00
20 changed files with 647 additions and 360 deletions

2
.gitignore vendored
View File

@@ -1,4 +1,4 @@
.secrets
.arduino_cache/ .arduino_cache/
bin/ bin/
build/ build/
src/secrets.h

View File

@@ -1,13 +1,11 @@
#include "Arduino_LED_Matrix.h" #include "Arduino_LED_Matrix.h"
#include "src/config.h" #include "src/config.h"
#include "src/pong_render.h" #include "src/renderer.h"
#include "src/pong_player.h" #include "src/engine.h"
#include "src/pong_ball.h" #include "src/paddle.h"
#include "src/arduino_network.h" #include "src/ball.h"
// create LED matrix object
ArduinoLEDMatrix matrix;
// initial pong frame matrix // initial pong frame matrix
byte frame[MATRIX_HEIGHT][MATRIX_WIDTH] = { byte frame[MATRIX_HEIGHT][MATRIX_WIDTH] = {
@@ -21,49 +19,100 @@ byte frame[MATRIX_HEIGHT][MATRIX_WIDTH] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
}; };
// players coordinates ArduinoLEDMatrix matrix;
int p1_start= 1;
int p2_start= 4;
// initials balls coordinates
int ball_x= BALL_RESET_X;
int ball_y= BALL_RESET_Y;
int need_refresh= 1;
int ball_delay= INITIAL_BALL_DELAY;
int need_refresh= true;
uint8_t hits= 0;
long exec_t2= millis(); long exec_t2= millis();
enum game_statuses : uint8_t {
TIMER,
RUN,
SCORE,
GAMEOVER,
WAIT,
};
game_statuses game_status= TIMER;
Ball ball(4, 6);
Paddle p1(1);
Paddle p2(4);
Engine engine(p1, p2, ball, INITIAL_BALL_DELAY);
Renderer renderer(p1, p2, ball, frame, matrix);
void setup() { void setup() {
Serial.begin(9600); Serial.begin(9600);
// start LED matrix // start LED matrix
matrix.begin(); matrix.begin();
pinMode(P1_BTN_UP, INPUT_PULLUP); pinMode(P1_BTN_UP, INPUT_PULLUP);
pinMode(P1_BTN_BOTTOM, INPUT_PULLUP); pinMode(P1_BTN_BOTTOM, INPUT_PULLUP);
pinMode(P2_BTN_UP, INPUT_PULLUP); pinMode(P2_BTN_UP, INPUT_PULLUP);
pinMode(P2_BTN_BOTTOM, INPUT_PULLUP); pinMode(P2_BTN_BOTTOM, INPUT_PULLUP);
randomSeed(millis()); randomSeed(millis());
setup_network();
} }
void loop() { void loop() {
long exec_t1= millis(); long exec_t1= millis();
pong_move_p1(p1_start, need_refresh);
pong_move_p2(p2_start, need_refresh); switch (game_status) {
if (exec_t1 - exec_t2 > ball_delay) {
move_ball(ball_x, ball_y, ball_delay, p1_start, p2_start, need_refresh); case TIMER:
exec_t2= exec_t1; for (int i = START_TIMER; i >= 0; i--) {
} renderer.render_timer(i);
if (need_refresh) { delay(1000);
render_matrix(frame, p1_start, p2_start, ball_x, ball_y); }
matrix.renderBitmap(frame, MATRIX_HEIGHT, MATRIX_WIDTH); game_status= RUN;
need_refresh= 0; // delay the first ball movement
exec_t2= millis() + FIRST_START_BALL_DELAY;
break;
case RUN:
need_refresh= check_paddle_movements(p1, p2);
if (exec_t1 - exec_t2 > engine.ball_movement_delay()) {
engine.run();
if (engine.get_event() == P1SCORE || engine.get_event() == P2SCORE)
game_status= SCORE;
exec_t2= exec_t1;
need_refresh= true;
}
// rerender matrix only if something is changed
if (need_refresh) {
renderer.render_matrix();
need_refresh= false;
}
break;
case SCORE:
delay(300);
renderer.render_score();
engine.restart_ball();
delay(1000);
if (p1.get_score() >= MAX_POINTS || p2.get_score() >= MAX_POINTS)
game_status= GAMEOVER;
else {
game_status= RUN;
// before move again the ball wait a second
renderer.render_matrix();
exec_t2= millis() + FIRST_START_BALL_DELAY;
}
break;
case GAMEOVER:
renderer.render_winner();
game_status= WAIT;
break;
case WAIT:
// keep showing the winner waiting for a restart
// restart game once one button is pressed
if (digitalRead(P1_BTN_UP) == LOW || digitalRead(P1_BTN_BOTTOM) == LOW || digitalRead(P2_BTN_UP) == LOW || digitalRead(P2_BTN_BOTTOM) == LOW) {
game_status= TIMER;
engine.reset();
}
break;
} }
delay(50); delay(50);
web_server();
} }

View File

@@ -1,141 +0,0 @@
#include "config.h"
#include "Arduino.h"
#include "WiFiS3.h"
char ssid[]= SECRET_SSID;
char pass[]= SECRET_PASS;
int status= WL_IDLE_STATUS;
WiFiServer server(80);
void printMacAddress(byte mac[]) {
for (int i = 0; i < 6; i++) {
if (i > 0) {
Serial.print(":");
}
if (mac[i] < 16) {
Serial.print("0");
}
Serial.print(mac[i], HEX);
}
Serial.println();
}
void printWifiData() {
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print your MAC address:
byte mac[6];
WiFi.macAddress(mac);
Serial.print("MAC address: ");
printMacAddress(mac);
}
void printCurrentNet() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print the MAC address of the router you're attached to:
byte bssid[6];
WiFi.BSSID(bssid);
Serial.print("BSSID: ");
printMacAddress(bssid);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.println(rssi);
// print the encryption type:
byte encryption = WiFi.encryptionType();
Serial.print("Encryption Type:");
Serial.println(encryption, HEX);
Serial.println();
}
void setup_network() {
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true);
}
String fv = WiFi.firmwareVersion();
Serial.print("Firmware version: ");
Serial.println(fv);
if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
Serial.println("Please upgrade the firmware");
}
// attempt to connect to WiFi network:
// Definisci i parametri di rete prima del loop di connessione
IPAddress local_IP(192, 168, 1, 200);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress dns(9,9,9,9);
WiFi.config(local_IP, gateway, subnet, dns);
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
// you're connected now, so print out the data:
Serial.println("You're connected to the network");
printCurrentNet();
printWifiData();
server.begin();
}
void web_server() {
WiFiClient client = server.available();
if (client) { // if you get a client,
Serial.println("new client"); // print a message out the serial port
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected()) { // loop while the client's connected
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out to the serial monitor
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println();
// the content of the HTTP response follows the header:
client.print("<p style=\"font-size:7vw;\">Click <a href=\"/H\">here</a> turn the LED on<br></p>");
client.print("<p style=\"font-size:7vw;\">Click <a href=\"/L\">here</a> turn the LED off<br></p>");
// The HTTP response ends with another blank line:
client.println();
// break out of the while loop:
break;
} else { // if you got a newline, then clear currentLine:
currentLine = "";
}
} else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
}
}
// close the connection:
client.stop();
Serial.println("client disconnected");
}
}

View File

@@ -1,11 +0,0 @@
#ifndef PONG_NETWORK_H
#define PONG_NETWORK_H
#include "Arduino.h"
void setup_network();
void printMacAddress(byte mac[]);
void printWifiData();
void printCurrentNet();
void web_server();
#endif

50
src/ball.cpp Normal file
View File

@@ -0,0 +1,50 @@
#include "ball.h"
void Ball::_init_directions(int8_t &_direction) {
if (random(2) == 0) _direction= 1;
else _direction= -1;
}
void Ball::move() {
if (!_direction_x) this -> _init_directions(_direction_x);
if (!_direction_y) this -> _init_directions(_direction_y);
// if (_x < 0 || _x > MATRIX_WIDTH-1 || _y < 0 || _y > MATRIX_HEIGHT-1) {
// this -> reset_position();
// }
if (_x + _direction_x >= 0 && _x + _direction_x < MATRIX_WIDTH)
_x+= _direction_x;
if (_y + _direction_y >= 0 && _y + _direction_y < MATRIX_HEIGHT)
_y+= _direction_y;
}
void Ball::bounce_on_pad() {
_direction_x *= -1;
}
void Ball::bounce_on_sides() {
_direction_y *= -1;
}
int8_t Ball::get_direction_x() {
return _direction_x;
}
int8_t Ball::get_direction_y() {
return _direction_y;
}
void Ball::reset_position () {
_x= BALL_RESET_X;
_y= BALL_RESET_Y;
this -> _init_directions(_direction_x);
this -> _init_directions(_direction_y);
}
uint8_t Ball::get_x() {
return _x;
}
uint8_t Ball::get_y() {
return _y;
}

27
src/ball.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef BALL_H
#define BALL_H
#include <Arduino.h>
#include "config.h"
class Ball {
private:
uint8_t _x, _y;
int8_t _direction_x, _direction_y;
void _init_directions(int8_t &_direction);
public:
Ball (uint8_t _x, uint8_t _y) : _x(_x), _y(_y) {}
void move();
void bounce_on_pad();
void bounce_on_sides();
int8_t get_direction_x();
int8_t get_direction_y();
void reset_position ();
uint8_t get_x();
uint8_t get_y();
};
#endif

View File

@@ -1,11 +1,3 @@
#if __has_include("secrets.h")
#include "secrets.h"
#else
#define SECRET_SSID "Fallback_SSID"
#define SECRET_PASS "Fallback_PASS"
#warning "⚠️ secrets.h not found"
#endif
#define P1_BTN_UP 12 #define P1_BTN_UP 12
#define P1_BTN_BOTTOM 11 #define P1_BTN_BOTTOM 11
#define P2_BTN_UP 10 #define P2_BTN_UP 10
@@ -15,5 +7,9 @@
#define MATRIX_HEIGHT 8 #define MATRIX_HEIGHT 8
#define BALL_RESET_X (MATRIX_WIDTH / 2) #define BALL_RESET_X (MATRIX_WIDTH / 2)
#define BALL_RESET_Y (MATRIX_HEIGHT / 2) #define BALL_RESET_Y (MATRIX_HEIGHT / 2)
#define BAR_LENGTH 3 #define PADDLE_LENGTH 3
#define INITIAL_BALL_DELAY 200 #define INITIAL_BALL_DELAY 200
#define MAX_POINTS 9
#define START_TIMER 3
#define FIRST_START_BALL_DELAY 500

81
src/engine.cpp Normal file
View File

@@ -0,0 +1,81 @@
#include "engine.h"
bool Engine::_check_pad_ball_collision(Paddle &p) {
uint8_t ppos= p.get_position();
for (int p= ppos; p < ppos + PADDLE_LENGTH; p++) {
if (_ball.get_y() == p) {
return true;
}
}
return false;
}
void Engine::run() {
// if (_event == P1SCORE || _event == P2SCORE) this -> _soft_reset();
_event= NONE;
_ball.move();
uint8_t bx= _ball.get_x();
uint8_t by= _ball.get_y();
int8_t ball_dir= _ball.get_direction_x();
// pad is 1 pixel far from the edge, so i need to calc this delta
// check also if the ball is already moving away, to skip useless checks
if (bx <= 1 && ball_dir < 0) {
// score the point only if ball reached the edge
if (this -> _check_pad_ball_collision(_p1) && bx <= 1) {
_ball.bounce_on_pad();
_event= P1_COLLISION;
_hits++;
}
else if (bx <= 0) {
// p2 scores
_p2.increase_score();
_event= P2SCORE;
return;
}
}
else if (bx >= MATRIX_WIDTH-2 && ball_dir > 0) {
// score the point only if ball reached the edge
if (this -> _check_pad_ball_collision(_p2) && bx >= MATRIX_WIDTH-2) {
_ball.bounce_on_pad();
_event= P2_COLLISION;
_hits++;
}
else if (bx >= MATRIX_WIDTH-1) {
// p1 scores
_p1.increase_score();
_event= P1SCORE;
return;
}
}
if (by == 0 || by == MATRIX_HEIGHT-1) {
_ball.bounce_on_sides();
_event= WALL_COLLISION;
}
if (_hits >= 6 && _ball_mv_delay >= 80) {
_hits= 0;
_ball_mv_delay -= 20;
}
}
uint8_t Engine::ball_movement_delay() {
return _ball_mv_delay;
}
EngineEvents Engine::get_event() {
return _event;
}
void Engine::restart_ball() {
_ball.reset_position();
_ball_mv_delay= INITIAL_BALL_DELAY;
}
void Engine::reset() {
this -> restart_ball();
_p1.reset();
_p2.reset();
}

35
src/engine.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef ENGINE_H
#define ENGINE_H
#include <Arduino.h>
#include "ball.h"
#include "paddle.h"
#include "config.h"
enum EngineEvents : uint8_t {NONE, P1SCORE, P2SCORE, P1_COLLISION, P2_COLLISION, WALL_COLLISION};
class Engine {
private:
Paddle& _p1;
Paddle& _p2;
Ball& _ball;
EngineEvents _event= NONE;
uint8_t _ball_mv_delay;
uint8_t _hits = 0;
bool _check_pad_ball_collision(Paddle &p);
public:
// inizialize Engine constructor, linking all args with private args
Engine(Paddle &p_one, Paddle &p_two, Ball &ball, uint8_t ball_mv_delay)
: _p1(p_one), _p2(p_two), _ball(ball), _ball_mv_delay(ball_mv_delay) {}
void run();
uint8_t ball_movement_delay();
EngineEvents get_event();
void restart_ball();
void reset();
};
#endif

184
src/font.h Normal file
View File

@@ -0,0 +1,184 @@
#ifndef FONT_H
#define FONT_H
#include <Arduino.h>
const uint32_t pone_wins[][4] = {
{
0x78,
0xc4847844,
0x440e000,
500
},
{
0x11,
0x1101501,
0x501f0000,
500
},
{
0xe,
0x400400,
0x400e0000,
500
},
{
0x9,
0xd00b00,
0x90090000,
500
},
{
0xf,
0x800f00,
0x100f0000,
500
}
};
const uint32_t ptwo_wins[][4] = {
{
0x79,
0xe48279e4,
0x1041e000,
500
},
{
0x11,
0x1101501,
0x501f0000,
500
},
{
0xe,
0x400400,
0x400e0000,
500
},
{
0x9,
0xd00b00,
0x90090000,
500
},
{
0xf,
0x800f00,
0x100f0000,
500
}
};
const byte font_pong[10][8][3] = {
// Number 0
{
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 1, 1, 1 },
{ 1, 0, 1 },
{ 1, 0, 1 },
{ 1, 0, 1 },
{ 1, 1, 1 },
{ 0, 0, 0 }
},
// Number 1
{
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 1, 1, 0 },
{ 0, 1, 0 },
{ 0, 1, 0 },
{ 0, 1, 0 },
{ 1, 1, 1 },
{ 0, 0, 0 }
},
// Number 2
{
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 1, 1, 1 },
{ 0, 0, 1 },
{ 1, 1, 1 },
{ 1, 0, 0 },
{ 1, 1, 1 },
{ 0, 0, 0 }
},
// Number 3
{
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 1, 1, 1 },
{ 0, 0, 1 },
{ 1, 1, 1 },
{ 0, 0, 1 },
{ 1, 1, 1 },
{ 0, 0, 0 }
},
// Number 4
{
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 1, 0, 1 },
{ 1, 0, 1 },
{ 1, 1, 1 },
{ 0, 0, 1 },
{ 0, 0, 1 },
{ 0, 0, 0 }
},
// Number 5
{
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 1, 1, 1 },
{ 1, 0, 0 },
{ 1, 1, 1 },
{ 0, 0, 1 },
{ 1, 1, 1 },
{ 0, 0, 0 }
},
// Number 6
{
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 1, 0, 0 },
{ 1, 0, 0 },
{ 1, 1, 1 },
{ 1, 0, 1 },
{ 1, 1, 1 },
{ 0, 0, 0 }
},
// Number 7
{
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 1, 1, 1 },
{ 0, 0, 1 },
{ 0, 0, 1 },
{ 0, 0, 1 },
{ 0, 0, 1 },
{ 0, 0, 0 }
},
// Number 8
{
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 1, 1, 1 },
{ 1, 0, 1 },
{ 1, 1, 1 },
{ 1, 0, 1 },
{ 1, 1, 1 },
{ 0, 0, 0 }
},
// Number 9
{
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 1, 1, 1 },
{ 1, 0, 1 },
{ 1, 1, 1 },
{ 0, 0, 1 },
{ 0, 0, 1 },
{ 0, 0, 0 }
},
};
#endif

54
src/paddle.cpp Normal file
View File

@@ -0,0 +1,54 @@
#include "paddle.h"
void Paddle::move_pad_up() {
if (_position > 0) {
_position -= 1;
}
}
void Paddle::move_pad_down() {
if (_position + _height < MATRIX_HEIGHT) {
_position += 1;
}
}
uint8_t Paddle::get_position() {
return _position;
}
bool Paddle::is_human() {
return _human;
}
void Paddle::increase_score() {
if (_score <= 9) _score += 1;
}
uint8_t Paddle::get_score() {
return _score;
}
void Paddle::reset() {
_score= 0;
}
bool check_paddle_movements(Paddle &p1, Paddle &p2) {
bool need_refresh= false;
if (digitalRead(P1_BTN_UP) == LOW) {
p1.move_pad_up();
need_refresh= true;
}
else if (digitalRead(P1_BTN_BOTTOM) == LOW) {
p1.move_pad_down();
need_refresh= true;
}
if (digitalRead(P2_BTN_UP) == LOW) {
p2.move_pad_up();
need_refresh= true;
}
else if (digitalRead(P2_BTN_BOTTOM) == LOW) {
p2.move_pad_down();
need_refresh= true;
}
return need_refresh;
}

29
src/paddle.h Normal file
View File

@@ -0,0 +1,29 @@
#ifndef PADDLE_H
#define PADDLE_H
#include <Arduino.h>
#include "config.h"
class Paddle {
private:
// define player coordinates
uint8_t _position;
uint8_t _height= PADDLE_LENGTH;
uint8_t _score= 0;
bool _human= true;
public:
Paddle (uint8_t _position) : _position(_position) {}
void move_pad_up();
void move_pad_down();
uint8_t get_position();
bool is_human();
void increase_score();
uint8_t get_score();
void reset();
};
bool check_paddle_movements(Paddle &p1, Paddle &p2);
#endif

View File

@@ -1,88 +0,0 @@
#include <Arduino.h>
#include "config.h"
#include "pong_player.h"
// used to increase speed when game is too easy
int hits= 0;
int p1_score= 0;
int p2_score= 0;
// initially ball has no movements
// once game/round starts, balls gets random x and y movements
int ball_move_x= 0;
int ball_move_y= 0;
void point_scored(int &ball_x, int &ball_y, int &ball_delay) {
ball_x= BALL_RESET_X;
ball_y= BALL_RESET_Y;
Serial.print("P1: ");
Serial.print(p1_score);
Serial.print(" - ");
Serial.print("P2: ");
Serial.print(p2_score);
Serial.println();
hits= 0;
ball_delay= INITIAL_BALL_DELAY;
}
void move_ball(int &ball_x, int &ball_y, int &ball_delay, int p1_start, int p2_start, int &need_refresh) {
need_refresh= 1;
if (ball_x < 0 || ball_x > MATRIX_WIDTH-1 || ball_y < 0 || ball_y > MATRIX_HEIGHT-1) {
// ball out of matrix limits
ball_x= BALL_RESET_X;
ball_y= BALL_RESET_Y;
return;
}
// if ball is not moving, get random direction
// this is the initial position
if (ball_move_x == 0 || ball_move_y == 0) {
// extract random number between 0 or 1 to select the directions
if (random(2) == 0) ball_move_x= 1;
else ball_move_x= -1;
if (random(2) == 0) ball_move_y= 1;
else ball_move_y= -1;
}
else if (ball_x == 0) {
// if p1 collision: reverse x, go left
if (!ball_player_collision(p1_start, ball_y)) {
// else p2 score, reset board
p2_score += 1;
Serial.println("Player 2 Scores");
point_scored(ball_x, ball_y, ball_delay);
}
else {
hits += 1;
ball_move_x= ball_move_x * -1;
}
}
else if (ball_x == MATRIX_WIDTH-1) {
if (!ball_player_collision(p2_start, ball_y)) {
// else p1 score, reset board
p1_score += 1;
Serial.println("Player 1 Scores");
point_scored(ball_x, ball_y, ball_delay);
}
else {
hits += 1;
ball_move_x= ball_move_x * -1;
}
}
if (ball_y == 0 || ball_y == MATRIX_HEIGHT-1) {
// reverse y, go down
ball_move_y= ball_move_y * -1;
}
if (hits >= 6 && ball_delay >= 80) {
// increase ball speed
hits = 0;
ball_delay -= 20;
}
ball_x+= ball_move_x;
ball_y+= ball_move_y;
}

View File

@@ -1,7 +0,0 @@
#ifndef PONG_BALL_H
#define PONG_BALL_H
void point_scored();
void move_ball(int &ball_x, int &ball_y, int &loop_delay, int p1_start, int p2_start, int &need_refresh);
#endif

View File

@@ -1,33 +0,0 @@
#include <Arduino.h>
#include "config.h"
int ball_player_collision(int player, int ball_y) {
for (int p= player; p < player + BAR_LENGTH; p++) {
if (ball_y == p) {
return 1;
}
}
return 0;
}
int pong_move_p1(int &p1_start, int &need_refresh) {
if (digitalRead(P1_BTN_UP) == LOW && p1_start > 0) {
p1_start -= 1;
need_refresh= 1;
}
else if (digitalRead(P1_BTN_BOTTOM) == LOW && p1_start < 5) {
p1_start += 1;
need_refresh= 1;
}
}
int pong_move_p2(int &p2_start, int &need_refresh) {
if (digitalRead(P2_BTN_UP) == LOW && p2_start > 0) {
p2_start -= 1;
need_refresh= 1;
}
else if (digitalRead(P2_BTN_BOTTOM) == LOW && p2_start < 5) {
p2_start += 1;
need_refresh= 1;
}
}

View File

@@ -1,8 +0,0 @@
#ifndef PONG_PLAYER_H
#define PONG_PLAYER_H
int ball_player_collision(int player, int ball_y);
int pong_move_p1(int &p1_start, int &need_refresh);
int pong_move_p2(int &p2_start, int &need_refresh);
#endif

View File

@@ -1,22 +0,0 @@
#include <Arduino.h>
#include "config.h"
void render_matrix(byte frame[MATRIX_HEIGHT][MATRIX_WIDTH], int p1_start, int p2_start, int ball_x, int ball_y) {
// clear
for (int x=0; x < MATRIX_WIDTH; x++) {
for (int y=0; y < MATRIX_HEIGHT; y++) {
frame[y][x]= 0;
}
}
// players coords
for (int i= p1_start; i < p1_start+BAR_LENGTH; i++) {
frame[i][0]= 1;
}
for (int i= p2_start; i < p2_start+BAR_LENGTH; i++) {
frame[i][MATRIX_WIDTH-1]= 1;
}
// ball coords
frame[ball_y][ball_x]= 1;
}

View File

@@ -1,9 +0,0 @@
#ifndef PONG_RENDER_H
#define PONG_RENDER_H
#include <Arduino.h>
#include "Arduino_LED_Matrix.h"
void render_matrix(byte frame[MATRIX_HEIGHT][MATRIX_WIDTH], int p1_start, int p2_start, int ball_x, int ball_y);
#endif

68
src/renderer.cpp Normal file
View File

@@ -0,0 +1,68 @@
#include "renderer.h"
void Renderer::_clear_matrix() {
for (int x=0; x < MATRIX_WIDTH; x++) {
for (int y=0; y < MATRIX_HEIGHT; y++) {
_frame[y][x]= 0;
}
}
}
void Renderer::render_timer(uint8_t seconds) {
this -> _clear_matrix();
for (int h=0; h < 8; h++) {
for (int w=0; w < 3; w++) {
_frame[h][w+5]= font_pong[seconds][h][w];
}
}
_matrix.renderBitmap(_frame, MATRIX_HEIGHT, MATRIX_WIDTH);
}
void Renderer::render_matrix() {
this -> _clear_matrix();
uint8_t p1pos= _p1.get_position();
uint8_t p2pos= _p2.get_position();
// players coords
for (int i= p1pos; i < p1pos+PADDLE_LENGTH; i++) {
_frame[i][0]= 1;
}
for (int i= p2pos; i < p2pos+PADDLE_LENGTH; i++) {
_frame[i][MATRIX_WIDTH-1]= 1;
}
// ball coords
uint8_t bx= _ball.get_x();
uint8_t by= _ball.get_y();
_frame[by][bx]= 1;
_matrix.renderBitmap(_frame, MATRIX_HEIGHT, MATRIX_WIDTH);
}
void Renderer::render_score() {
this -> _clear_matrix();
_frame[4][5]= 1;
_frame[4][6]= 1;
for (int h=0; h < 8; h++) {
for (int w=0; w < 3; w++) {
_frame[h][w+1]= font_pong[_p1.get_score()][h][w];
}
}
for (int h=0; h < 8; h++) {
for (int w=0; w < 3; w++) {
_frame[h][w+8]= font_pong[_p2.get_score()][h][w];
}
}
_matrix.renderBitmap(_frame, MATRIX_HEIGHT, MATRIX_WIDTH);
}
void Renderer::render_winner() {
this -> _clear_matrix();
// check winner
if (_p1.get_score() > _p2.get_score())
_matrix.loadSequence(pone_wins);
else
_matrix.loadSequence(ptwo_wins);
_matrix.play(true);
}

33
src/renderer.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef RENDERER_H
#define RENDERER_H
#include <Arduino.h>
#include "Arduino_LED_Matrix.h"
#include "config.h"
#include "font.h"
#include "paddle.h"
#include "ball.h"
class Renderer {
private:
// define player coordinates
Paddle& _p1;
Paddle& _p2;
Ball& _ball;
byte (&_frame)[MATRIX_HEIGHT][MATRIX_WIDTH];
ArduinoLEDMatrix& _matrix;
void _clear_matrix();
public:
Renderer (Paddle &p1, Paddle &p2, Ball &ball, byte (&frame)[MATRIX_HEIGHT][MATRIX_WIDTH], ArduinoLEDMatrix &matrix)
: _p1(p1), _p2(p2), _ball(ball), _frame(frame), _matrix(matrix) {}
void render_timer(uint8_t seconds);
void render_matrix();
void render_score();
void render_winner();
};
#endif