20 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
andrea
6e5fc8ea10 change digital pins to avoid collisions with pin13 for L Led on the board
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-15 22:43:00 +01:00
andrea
28f029ce03 update ci.yml with new libs structure
Some checks failed
Arduino Pong CI / build (ubuntu-latest) (push) Has been cancelled
Arduino Pong CI / build (macos-latest) (push) Has been cancelled
Arduino Pong CI / build (windows-latest) (push) Has been cancelled
2026-03-15 21:15:49 +01:00
andrea
cb42a45aa7 move all libs into src
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-15 21:14:04 +01:00
andrea
c47291e258 minors
Some checks failed
Arduino Pong CI / build (ubuntu-latest) (push) Has been cancelled
Arduino Pong CI / build (windows-latest) (push) Has been cancelled
Arduino Pong CI / build (macos-latest) (push) Has been cancelled
Arduino Pong CD / release (push) Has been cancelled
2026-03-15 20:29:56 +01:00
andrea
fec4db0c5d improve rerender logics
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-15 20:23:52 +01:00
andrea
7c065d8799 updated ci.yml
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-15 20:09:21 +01:00
21 changed files with 666 additions and 211 deletions

View File

@@ -7,6 +7,8 @@ on:
- 'arduino_pong.ino' - 'arduino_pong.ino'
- 'Makefile' - 'Makefile'
- '.github/workflows/ci.yml' - '.github/workflows/ci.yml'
- 'src/*.cpp'
- 'src/*.h'
jobs: jobs:
build: build:

View File

@@ -8,7 +8,7 @@ A classic implementation of the Pong game developed specifically for the Arduino
# 📹 Preview # 📹 Preview
![Pong](preview.png) ![Pong](assets/preview.png)
Youtube: https://youtu.be/ouLBTDjpKqc Youtube: https://youtu.be/ouLBTDjpKqc

View File

@@ -1,61 +1,118 @@
#include "Arduino_LED_Matrix.h" #include "Arduino_LED_Matrix.h"
#include "config.h" #include "src/config.h"
#include "pong_render.h" #include "src/renderer.h"
#include "pong_player.h" #include "src/engine.h"
#include "pong_ball.h" #include "src/paddle.h"
#include "src/ball.h"
// create LED matrix object
ArduinoLEDMatrix matrix;
// initial pong frame // initial pong frame matrix
byte frame[MATRIX_HEIGHT][MATRIX_WIDTH] = { 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 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 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 loop_delay= INITIAL_LOOP_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(115200);
Serial.begin(9600); Serial.begin(9600);
// stard 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(analogRead(0)); randomSeed(millis());
} }
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) {
render_matrix(frame, p1_start, p2_start, need_refresh, ball_x, ball_y);
if (exec_t1 - exec_t2 > loop_delay) { case TIMER:
move_ball(ball_x, ball_y, loop_delay, p1_start, p2_start, need_refresh); for (int i = START_TIMER; i >= 0; i--) {
exec_t2= exec_t1; renderer.render_timer(i);
delay(1000);
}
game_status= RUN;
// 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;
} }
matrix.renderBitmap(frame, MATRIX_HEIGHT, MATRIX_WIDTH);
delay(50); delay(50);
} }

View File

Before

Width:  |  Height:  |  Size: 847 KiB

After

Width:  |  Height:  |  Size: 847 KiB

View File

@@ -1,11 +0,0 @@
#define P1_BTN_UP 13
#define P1_BTN_BOTTOM 12
#define P2_BTN_UP 11
#define P2_BTN_BOTTOM 10
#define MATRIX_WIDTH 12
#define MATRIX_HEIGHT 8
#define BALL_RESET_X (MATRIX_WIDTH / 2)
#define BALL_RESET_Y (MATRIX_HEIGHT / 2)
#define BAR_LENGTH 3
#define INITIAL_LOOP_DELAY 200

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 &loop_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;
loop_delay= INITIAL_LOOP_DELAY;
}
void move_ball(int &ball_x, int &ball_y, int &loop_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, loop_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, loop_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 && loop_delay >= 80) {
// increase ball speed
hits = 0;
loop_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,24 +0,0 @@
#include <Arduino.h>
#include "config.h"
void render_matrix(byte frame[MATRIX_HEIGHT][MATRIX_WIDTH], int p1_start, int p2_start, int &need_refresh, int ball_x, int ball_y) {
if (!need_refresh) return;
need_refresh= 0;
// 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 &need_refresh, int ball_x, int ball_y);
#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

15
src/config.h Normal file
View File

@@ -0,0 +1,15 @@
#define P1_BTN_UP 12
#define P1_BTN_BOTTOM 11
#define P2_BTN_UP 10
#define P2_BTN_BOTTOM 9
#define MATRIX_WIDTH 12
#define MATRIX_HEIGHT 8
#define BALL_RESET_X (MATRIX_WIDTH / 2)
#define BALL_RESET_Y (MATRIX_HEIGHT / 2)
#define PADDLE_LENGTH 3
#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

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