choose game mode

pvp, pvc, cvc
This commit is contained in:
andrea
2026-03-21 10:24:15 +01:00
parent 7f63ae9a31
commit a9aed6b8d0
7 changed files with 292 additions and 208 deletions

View File

@@ -33,15 +33,19 @@ enum game_statuses : uint8_t {
GAMEOVER, GAMEOVER,
WAIT, WAIT,
}; };
game_statuses game_status= TIMER; game_statuses game_status= MENU;
Ball ball(4, 6); Ball ball(4, 6);
HumanPaddle p1(1, P1_BTN_UP, P1_BTN_BOTTOM);
// HumanPaddle p2(4, P2_BTN_UP, P2_BTN_BOTTOM); Paddle* p1= nullptr;
// BotPaddle p1(1, 0, 2); Paddle* p2= nullptr;
BotPaddle p2(4, MATRIX_WIDTH-1, 1); HumanPaddle human_pad1(1, P1_BTN_UP, P1_BTN_BOTTOM);
Engine engine(p1, p2, ball, INITIAL_BALL_DELAY); HumanPaddle human_pad2(4, P2_BTN_UP, P2_BTN_BOTTOM);
Renderer renderer(p1, p2, ball, frame, matrix); BotPaddle bot_pad1(1, 0, 2);
BotPaddle bot_pad2(4, MATRIX_WIDTH-1, 2);
Engine engine(ball, INITIAL_BALL_DELAY);
Renderer renderer(ball, frame, matrix);
void setup() { void setup() {
Serial.begin(9600); Serial.begin(9600);
@@ -63,9 +67,31 @@ void loop() {
case MENU: case MENU:
// show menu on the matrix // show menu on the matrix
// matrix.renderBitmap(pvp_frame, MATRIX_HEIGHT, MATRIX_WIDTH);
// 1. P vs P // 1. P vs P
if (digitalRead(P1_BTN_UP) == LOW) {
p1= &human_pad1;
p2= &human_pad2;
engine.set_players(p1, p2);
renderer.set_players(p1, p2);
game_status= TIMER;
}
// 2. P vs CPU // 2. P vs CPU
else if (digitalRead(P1_BTN_BOTTOM) == LOW) {
p1= &human_pad1;
p2= &bot_pad2;
engine.set_players(p1, p2);
renderer.set_players(p1, p2);
game_status= TIMER;
}
// 3. CPU vs CPU // 3. CPU vs CPU
else if (digitalRead(P2_BTN_UP) == LOW) {
p1= &bot_pad1;
p2= &bot_pad2;
engine.set_players(p1, p2);
renderer.set_players(p1, p2);
game_status= TIMER;
}
// slideshow menu // slideshow menu
break; break;
@@ -101,7 +127,7 @@ void loop() {
renderer.render_score(); renderer.render_score();
engine.restart_ball(); engine.restart_ball();
delay(1000); delay(1000);
if (p1.get_score() >= MAX_POINTS || p2.get_score() >= MAX_POINTS) if (p1 -> get_score() >= MAX_POINTS || p2 -> get_score() >= MAX_POINTS)
game_status= GAMEOVER; game_status= GAMEOVER;
else { else {
game_status= RUN; game_status= RUN;

View File

@@ -1,7 +1,7 @@
#include "engine.h" #include "engine.h"
bool Engine::_check_pad_ball_collision(Paddle &p) { bool Engine::_check_pad_ball_collision(Paddle *p) {
uint8_t ppos= p.get_position(); uint8_t ppos= p -> get_position();
for (int p= ppos; p < ppos + PADDLE_LENGTH; p++) { for (int p= ppos; p < ppos + PADDLE_LENGTH; p++) {
if (_ball.get_y() == p) { if (_ball.get_y() == p) {
return true; return true;
@@ -29,7 +29,7 @@ void Engine::run() {
} }
else if (bx <= 0) { else if (bx <= 0) {
// p2 scores // p2 scores
_p2.increase_score(); _p2 -> increase_score();
_event= P2SCORE; _event= P2SCORE;
return; return;
} }
@@ -43,7 +43,7 @@ void Engine::run() {
} }
else if (bx >= MATRIX_WIDTH-1) { else if (bx >= MATRIX_WIDTH-1) {
// p1 scores // p1 scores
_p1.increase_score(); _p1 -> increase_score();
_event= P1SCORE; _event= P1SCORE;
return; return;
} }
@@ -60,13 +60,18 @@ void Engine::run() {
} }
} }
void Engine::set_players(Paddle *p1, Paddle *p2) {
_p1= p1;
_p2= p2;
}
bool Engine::control_players() { bool Engine::control_players() {
bool need_refresh= false; bool need_refresh= false;
if (_p1.is_human()) need_refresh |= _p1.check_pad_movement(); if (_p1 -> is_human()) need_refresh |= _p1 -> check_pad_movement();
else need_refresh |= _p1.check_pad_movement(_ball); else need_refresh |= _p1 -> check_pad_movement(_ball);
if (_p2.is_human()) need_refresh |= _p2.check_pad_movement(); if (_p2 -> is_human()) need_refresh |= _p2 -> check_pad_movement();
else need_refresh |= _p2.check_pad_movement(_ball); else need_refresh |= _p2 -> check_pad_movement(_ball);
return need_refresh; return need_refresh;
} }
@@ -86,6 +91,6 @@ void Engine::restart_ball() {
void Engine::reset() { void Engine::reset() {
this -> restart_ball(); this -> restart_ball();
_p1.reset(); _p1 -> reset();
_p2.reset(); _p2 -> reset();
} }

View File

@@ -11,21 +11,22 @@ enum EngineEvents : uint8_t {NONE, P1SCORE, P2SCORE, P1_COLLISION, P2_COLLISION,
class Engine { class Engine {
private: private:
Paddle& _p1; Paddle* _p1;
Paddle& _p2; Paddle* _p2;
Ball& _ball; Ball& _ball;
EngineEvents _event= NONE; EngineEvents _event= NONE;
uint8_t _ball_mv_delay; uint8_t _ball_mv_delay;
uint8_t _hits = 0; uint8_t _hits = 0;
bool _check_pad_ball_collision(Paddle &p); bool _check_pad_ball_collision(Paddle *p);
public: public:
// inizialize Engine constructor, linking all args with private args // inizialize Engine constructor, linking all args with private args
Engine(Paddle &p_one, Paddle &p_two, Ball &ball, uint8_t ball_mv_delay) Engine(Ball &ball, uint8_t ball_mv_delay)
: _p1(p_one), _p2(p_two), _ball(ball), _ball_mv_delay(ball_mv_delay) {} : _ball(ball), _ball_mv_delay(ball_mv_delay) {}
void run(); void run();
void set_players(Paddle *p_one, Paddle *p_two);
bool control_players(); bool control_players();
uint8_t ball_movement_delay(); uint8_t ball_movement_delay();
EngineEvents get_event(); EngineEvents get_event();

214
src/font.cpp Normal file
View File

@@ -0,0 +1,214 @@
#include "font.h";
const uint32_t pone_wins[5][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[5][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 }
},
};
const byte pvp_frame[MATRIX_HEIGHT][MATRIX_WIDTH] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0 },
{ 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0 },
{ 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0 },
{ 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 1, 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, 0, 0, 0 }
};
const byte pvc_frame[MATRIX_HEIGHT][MATRIX_WIDTH] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0 },
{ 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 },
{ 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0 },
{ 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 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, 0 }
};
const byte cvc_frame[MATRIX_HEIGHT][MATRIX_WIDTH] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 },
{ 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0 },
{ 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0 },
{ 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 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, 0 }
};
const byte (*game_modes[3])[12]= {pvp_frame, pvc_frame, cvc_frame};

View File

@@ -2,183 +2,15 @@
#define FONT_H #define FONT_H
#include <Arduino.h> #include <Arduino.h>
#include "config.h"
const uint32_t pone_wins[][4] = { extern const uint32_t pone_wins[5][4];
{ extern const uint32_t ptwo_wins[5][4];
0x78, extern const byte font_pong[10][8][3];
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] = { extern const byte pvp_frame[MATRIX_HEIGHT][MATRIX_WIDTH];
// Number 0 extern const byte pvc_frame[MATRIX_HEIGHT][MATRIX_WIDTH];
{ extern const byte cvc_frame[MATRIX_HEIGHT][MATRIX_WIDTH];
{ 0, 0, 0 }, extern const byte (*game_modes[3])[MATRIX_WIDTH];
{ 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 #endif

View File

@@ -9,6 +9,11 @@ void Renderer::_clear_matrix() {
} }
} }
void Renderer::set_players(Paddle *p1, Paddle *p2) {
_p1= p1;
_p2= p2;
}
void Renderer::render_timer(uint8_t seconds) { void Renderer::render_timer(uint8_t seconds) {
this -> _clear_matrix(); this -> _clear_matrix();
@@ -22,8 +27,8 @@ void Renderer::render_timer(uint8_t seconds) {
void Renderer::render_matrix() { void Renderer::render_matrix() {
this -> _clear_matrix(); this -> _clear_matrix();
uint8_t p1pos= _p1.get_position(); uint8_t p1pos= _p1 -> get_position();
uint8_t p2pos= _p2.get_position(); uint8_t p2pos= _p2 -> get_position();
// players coords // players coords
for (int i= p1pos; i < p1pos+PADDLE_LENGTH; i++) { for (int i= p1pos; i < p1pos+PADDLE_LENGTH; i++) {
_frame[i][0]= 1; _frame[i][0]= 1;
@@ -46,12 +51,12 @@ void Renderer::render_score() {
for (int h=0; h < 8; h++) { for (int h=0; h < 8; h++) {
for (int w=0; w < 3; w++) { for (int w=0; w < 3; w++) {
_frame[h][w+1]= font_pong[_p1.get_score()][h][w]; _frame[h][w+1]= font_pong[_p1 -> get_score()][h][w];
} }
} }
for (int h=0; h < 8; h++) { for (int h=0; h < 8; h++) {
for (int w=0; w < 3; w++) { for (int w=0; w < 3; w++) {
_frame[h][w+8]= font_pong[_p2.get_score()][h][w]; _frame[h][w+8]= font_pong[_p2 -> get_score()][h][w];
} }
} }
_matrix.renderBitmap(_frame, MATRIX_HEIGHT, MATRIX_WIDTH); _matrix.renderBitmap(_frame, MATRIX_HEIGHT, MATRIX_WIDTH);
@@ -60,7 +65,7 @@ void Renderer::render_score() {
void Renderer::render_winner() { void Renderer::render_winner() {
this -> _clear_matrix(); this -> _clear_matrix();
// check winner // check winner
if (_p1.get_score() > _p2.get_score()) if (_p1 -> get_score() > _p2 -> get_score())
_matrix.loadSequence(pone_wins); _matrix.loadSequence(pone_wins);
else else
_matrix.loadSequence(ptwo_wins); _matrix.loadSequence(ptwo_wins);

View File

@@ -12,8 +12,8 @@ class Renderer {
private: private:
// define player coordinates // define player coordinates
Paddle& _p1; Paddle* _p1;
Paddle& _p2; Paddle* _p2;
Ball& _ball; Ball& _ball;
byte (&_frame)[MATRIX_HEIGHT][MATRIX_WIDTH]; byte (&_frame)[MATRIX_HEIGHT][MATRIX_WIDTH];
ArduinoLEDMatrix& _matrix; ArduinoLEDMatrix& _matrix;
@@ -21,9 +21,10 @@ class Renderer {
void _clear_matrix(); void _clear_matrix();
public: public:
Renderer (Paddle &p1, Paddle &p2, Ball &ball, byte (&frame)[MATRIX_HEIGHT][MATRIX_WIDTH], ArduinoLEDMatrix &matrix) Renderer (Ball &ball, byte (&frame)[MATRIX_HEIGHT][MATRIX_WIDTH], ArduinoLEDMatrix &matrix)
: _p1(p1), _p2(p2), _ball(ball), _frame(frame), _matrix(matrix) {} : _ball(ball), _frame(frame), _matrix(matrix) {}
void set_players(Paddle *p1, Paddle *p2);
void render_timer(uint8_t seconds); void render_timer(uint8_t seconds);
void render_matrix(); void render_matrix();
void render_score(); void render_score();