From b3f6aeb3fefe76fbb7136ba22f9a43d4bb705bb1 Mon Sep 17 00:00:00 2001 From: andrea Date: Mon, 16 Mar 2026 22:37:53 +0100 Subject: [PATCH] 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 --- arduino_pong.ino | 69 +++++++++++++---- src/config.h | 4 + src/font.h | 184 ++++++++++++++++++++++++++++++++++++++++++++ src/pong_ball.cpp | 52 ++++++++----- src/pong_ball.h | 3 +- src/pong_render.cpp | 63 +++++++++++++-- src/pong_render.h | 6 +- 7 files changed, 339 insertions(+), 42 deletions(-) create mode 100644 src/font.h diff --git a/arduino_pong.ino b/arduino_pong.ino index ebae28e..a8cb22b 100644 --- a/arduino_pong.ino +++ b/arduino_pong.ino @@ -21,8 +21,8 @@ byte frame[MATRIX_HEIGHT][MATRIX_WIDTH] = { }; // players coordinates -int p1_start= 1; -int p2_start= 4; +int players_coords[2]= {1, 4}; +int players_scores[2]= {0, 0}; // initials balls coordinates int ball_x= BALL_RESET_X; @@ -32,6 +32,9 @@ int need_refresh= 1; int ball_delay= INITIAL_BALL_DELAY; +bool game_over= false; +bool go= true; + long exec_t2= millis(); @@ -39,6 +42,7 @@ void setup() { Serial.begin(9600); // start LED matrix matrix.begin(); + pinMode(P1_BTN_UP, INPUT_PULLUP); pinMode(P1_BTN_BOTTOM, INPUT_PULLUP); pinMode(P2_BTN_UP, INPUT_PULLUP); @@ -48,17 +52,56 @@ void setup() { } void loop() { - long exec_t1= millis(); - pong_move_p1(p1_start, need_refresh); - pong_move_p2(p2_start, need_refresh); - if (exec_t1 - exec_t2 > ball_delay) { - move_ball(ball_x, ball_y, ball_delay, p1_start, p2_start, need_refresh); - exec_t2= exec_t1; - } - if (need_refresh) { - render_matrix(frame, p1_start, p2_start, ball_x, ball_y); + for (int i = START_TIMER; i >= 0; i--) { + render_timer(frame, i); + delay(1000); matrix.renderBitmap(frame, MATRIX_HEIGHT, MATRIX_WIDTH); - need_refresh= 0; } - delay(50); + + game_over= false; + go= true; + + // delay the first ball movement + exec_t2= millis() + FIRST_START_BALL_DELAY; + + while (go) { + long exec_t1= millis(); + pong_move_p1(players_coords[0], need_refresh); + pong_move_p2(players_coords[1], need_refresh); + if (exec_t1 - exec_t2 > ball_delay) { + bool scored= move_ball(ball_x, ball_y, ball_delay, players_coords, players_scores, need_refresh); + if (scored) { + render_score(frame, players_scores); + matrix.renderBitmap(frame, MATRIX_HEIGHT, MATRIX_WIDTH); + delay(1000); + if (players_scores[0] >= MAX_POINTS || players_scores[1] >= MAX_POINTS) { + render_winner(frame, matrix, players_scores); + need_refresh= 0; + game_over= true; + } + // delay the ball movement after score + exec_t2= millis() + FIRST_START_BALL_DELAY; + } else exec_t2= exec_t1; + } + + // rerender matrix only if something is changed + if (need_refresh) { + render_matrix(frame, players_coords, ball_x, ball_y); + matrix.renderBitmap(frame, MATRIX_HEIGHT, MATRIX_WIDTH); + need_refresh= 0; + } + if (!game_over) delay(50); + + // keep showing the winner waiting for a restart + while (game_over) { + // 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) { + go= false; + game_over= false; + players_scores[0]= 0; + players_scores[1]= 0; + } + delay(100); + } + } } diff --git a/src/config.h b/src/config.h index c20cf80..60c907f 100644 --- a/src/config.h +++ b/src/config.h @@ -9,3 +9,7 @@ #define BALL_RESET_Y (MATRIX_HEIGHT / 2) #define BAR_LENGTH 3 #define INITIAL_BALL_DELAY 200 + +#define MAX_POINTS 9 +#define START_TIMER 3 +#define FIRST_START_BALL_DELAY 500 diff --git a/src/font.h b/src/font.h new file mode 100644 index 0000000..2f5bfcd --- /dev/null +++ b/src/font.h @@ -0,0 +1,184 @@ +#ifndef FONT_H +#define FONT_H + +#include + +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 diff --git a/src/pong_ball.cpp b/src/pong_ball.cpp index f7c9139..137bccc 100644 --- a/src/pong_ball.cpp +++ b/src/pong_ball.cpp @@ -5,54 +5,61 @@ // 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) { +void random_ball_movement(int &ball_move_x, int &ball_move_y) { + 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; +} + +void point_scored(int &ball_x, int &ball_y, int &ball_delay, int players_scores[2], int &ball_move_x, int &ball_move_y) { ball_x= BALL_RESET_X; ball_y= BALL_RESET_Y; + random_ball_movement(ball_move_x, ball_move_y); + Serial.print("P1: "); - Serial.print(p1_score); + Serial.print(players_scores[0]); Serial.print(" - "); Serial.print("P2: "); - Serial.print(p2_score); + Serial.print(players_scores[1]); 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; +bool move_ball(int &ball_x, int &ball_y, int &ball_delay, int players_coords[2], int players_scores[2], int &need_refresh) { 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; + return false; } + + need_refresh= 1; + bool scored= false; // 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; + random_ball_movement(ball_move_x, ball_move_y); } else if (ball_x == 0) { // if p1 collision: reverse x, go left - if (!ball_player_collision(p1_start, ball_y)) { + if (!ball_player_collision(players_coords[0], ball_y)) { // else p2 score, reset board - p2_score += 1; + players_scores[1] += 1; + scored= true; Serial.println("Player 2 Scores"); - point_scored(ball_x, ball_y, ball_delay); + point_scored(ball_x, ball_y, ball_delay, players_scores, ball_move_x, ball_move_y); + return true; } else { hits += 1; @@ -60,11 +67,13 @@ void move_ball(int &ball_x, int &ball_y, int &ball_delay, int p1_start, int p2_s } } else if (ball_x == MATRIX_WIDTH-1) { - if (!ball_player_collision(p2_start, ball_y)) { + if (!ball_player_collision(players_coords[1], ball_y)) { // else p1 score, reset board - p1_score += 1; + players_scores[0] += 1; + scored= true; Serial.println("Player 1 Scores"); - point_scored(ball_x, ball_y, ball_delay); + point_scored(ball_x, ball_y, ball_delay, players_scores, ball_move_x, ball_move_y); + return true; } else { hits += 1; @@ -79,10 +88,11 @@ void move_ball(int &ball_x, int &ball_y, int &ball_delay, int p1_start, int p2_s if (hits >= 6 && ball_delay >= 80) { // increase ball speed - hits = 0; - ball_delay -= 20; + hits= 0; + ball_delay-= 20; } ball_x+= ball_move_x; ball_y+= ball_move_y; + return scored; } diff --git a/src/pong_ball.h b/src/pong_ball.h index 46cfb51..4c236ea 100644 --- a/src/pong_ball.h +++ b/src/pong_ball.h @@ -1,7 +1,6 @@ #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); +bool move_ball(int &ball_x, int &ball_y, int &loop_delay, int players_coords[2], int players_scores[2], int &need_refresh); #endif diff --git a/src/pong_render.cpp b/src/pong_render.cpp index 01830a2..a32e6aa 100644 --- a/src/pong_render.cpp +++ b/src/pong_render.cpp @@ -1,22 +1,75 @@ #include +#include "Arduino_LED_Matrix.h" #include "config.h" +#include "font.h" -void render_matrix(byte frame[MATRIX_HEIGHT][MATRIX_WIDTH], int p1_start, int p2_start, int ball_x, int ball_y) { - // clear +void clear_matrix(byte frame[MATRIX_HEIGHT][MATRIX_WIDTH]) { for (int x=0; x < MATRIX_WIDTH; x++) { for (int y=0; y < MATRIX_HEIGHT; y++) { frame[y][x]= 0; } } - +} + +void render_matrix(byte frame[MATRIX_HEIGHT][MATRIX_WIDTH], int players_coords[2], int ball_x, int ball_y) { + clear_matrix(frame); + int player_one= players_coords[0]; + int player_two= players_coords[1]; // players coords - for (int i= p1_start; i < p1_start+BAR_LENGTH; i++) { + for (int i= player_one; i < player_one+BAR_LENGTH; i++) { frame[i][0]= 1; } - for (int i= p2_start; i < p2_start+BAR_LENGTH; i++) { + for (int i= player_two; i < player_two+BAR_LENGTH; i++) { frame[i][MATRIX_WIDTH-1]= 1; } // ball coords frame[ball_y][ball_x]= 1; } + +void render_score(byte frame[MATRIX_HEIGHT][MATRIX_WIDTH], int players_scores[2]) { + clear_matrix(frame); + int player_one= players_scores[0]; + int player_two= players_scores[1]; + if (player_one > 9) player_one = 9; + if (player_two > 9) player_two = 9; + + // player score separator (-) + 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[player_one][h][w]; + } + } + for (int h=0; h < 8; h++) { + for (int w=0; w < 3; w++) { + frame[h][w+8]= font_pong[player_two][h][w]; + } + } +} + +void render_timer(byte frame[MATRIX_HEIGHT][MATRIX_WIDTH], int seconds) { + clear_matrix(frame); + + for (int h=0; h < 8; h++) { + for (int w=0; w < 3; w++) { + frame[h][w+5]= font_pong[seconds][h][w]; + } + } +} + +void render_winner(byte frame[MATRIX_HEIGHT][MATRIX_WIDTH], ArduinoLEDMatrix &matrix, int players_scores[2]) { + clear_matrix(frame); + // check winner + if (players_scores[0] > players_scores[1]) { + Serial.println("Player 1 wins!!!"); + matrix.loadSequence(pone_wins); + } + else { + Serial.println("Player 2 wins!!!"); + matrix.loadSequence(ptwo_wins); + } + matrix.play(true); +} diff --git a/src/pong_render.h b/src/pong_render.h index 11710f9..5d935e1 100644 --- a/src/pong_render.h +++ b/src/pong_render.h @@ -3,7 +3,11 @@ #include #include "Arduino_LED_Matrix.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); +void render_matrix(byte frame[MATRIX_HEIGHT][MATRIX_WIDTH], int players_coords[2], int ball_x, int ball_y); +void render_score(byte frame[MATRIX_HEIGHT][MATRIX_WIDTH], int players_scores[2]); +void render_timer(byte frame[MATRIX_HEIGHT][MATRIX_WIDTH], int seconds); +void render_winner(byte frame[MATRIX_HEIGHT][MATRIX_WIDTH], ArduinoLEDMatrix &matrix, int players_scores[2]); #endif