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,
WAIT,
};
game_statuses game_status= TIMER;
game_statuses game_status= MENU;
Ball ball(4, 6);
HumanPaddle p1(1, P1_BTN_UP, P1_BTN_BOTTOM);
// HumanPaddle p2(4, P2_BTN_UP, P2_BTN_BOTTOM);
// BotPaddle p1(1, 0, 2);
BotPaddle p2(4, MATRIX_WIDTH-1, 1);
Engine engine(p1, p2, ball, INITIAL_BALL_DELAY);
Renderer renderer(p1, p2, ball, frame, matrix);
Paddle* p1= nullptr;
Paddle* p2= nullptr;
HumanPaddle human_pad1(1, P1_BTN_UP, P1_BTN_BOTTOM);
HumanPaddle human_pad2(4, P2_BTN_UP, P2_BTN_BOTTOM);
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() {
Serial.begin(9600);
@@ -63,9 +67,31 @@ void loop() {
case MENU:
// show menu on the matrix
// matrix.renderBitmap(pvp_frame, MATRIX_HEIGHT, MATRIX_WIDTH);
// 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
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
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
break;
@@ -101,7 +127,7 @@ void loop() {
renderer.render_score();
engine.restart_ball();
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;
else {
game_status= RUN;

View File

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

View File

@@ -11,21 +11,22 @@ enum EngineEvents : uint8_t {NONE, P1SCORE, P2SCORE, P1_COLLISION, P2_COLLISION,
class Engine {
private:
Paddle& _p1;
Paddle& _p2;
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);
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) {}
Engine(Ball &ball, uint8_t ball_mv_delay)
: _ball(ball), _ball_mv_delay(ball_mv_delay) {}
void run();
void set_players(Paddle *p_one, Paddle *p_two);
bool control_players();
uint8_t ball_movement_delay();
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
#include <Arduino.h>
#include "config.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
}
};
extern const uint32_t pone_wins[5][4];
extern const uint32_t ptwo_wins[5][4];
extern const byte font_pong[10][8][3];
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 }
},
};
extern const byte pvp_frame[MATRIX_HEIGHT][MATRIX_WIDTH];
extern const byte pvc_frame[MATRIX_HEIGHT][MATRIX_WIDTH];
extern const byte cvc_frame[MATRIX_HEIGHT][MATRIX_WIDTH];
extern const byte (*game_modes[3])[MATRIX_WIDTH];
#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) {
this -> _clear_matrix();
@@ -22,8 +27,8 @@ void Renderer::render_timer(uint8_t seconds) {
void Renderer::render_matrix() {
this -> _clear_matrix();
uint8_t p1pos= _p1.get_position();
uint8_t p2pos= _p2.get_position();
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;
@@ -46,12 +51,12 @@ void Renderer::render_score() {
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];
_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];
_frame[h][w+8]= font_pong[_p2 -> get_score()][h][w];
}
}
_matrix.renderBitmap(_frame, MATRIX_HEIGHT, MATRIX_WIDTH);
@@ -60,7 +65,7 @@ void Renderer::render_score() {
void Renderer::render_winner() {
this -> _clear_matrix();
// check winner
if (_p1.get_score() > _p2.get_score())
if (_p1 -> get_score() > _p2 -> get_score())
_matrix.loadSequence(pone_wins);
else
_matrix.loadSequence(ptwo_wins);

View File

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