diff --git a/arduino_pong.ino b/arduino_pong.ino index 42b3332..6cf9f6d 100644 --- a/arduino_pong.ino +++ b/arduino_pong.ino @@ -27,6 +27,7 @@ long exec_t2= millis(); enum game_statuses : uint8_t { MENU, + MENU_BOT_SKILLS, TIMER, RUN, SCORE, @@ -45,12 +46,14 @@ 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); +BotPaddle bot_pad1(1, 0); +BotPaddle bot_pad2(4, MATRIX_WIDTH-1); uint8_t current_gmode_idx= 0; -bool update_menu= 1; -bool mode_selected= 0; +bool update_menu= true; +bool mode_selected= false; +uint8_t current_bot_menu_idx= 0; +bool update_menu_bot_skills= true; Engine engine(ball, INITIAL_BALL_DELAY); Renderer renderer(ball, frame, matrix); @@ -81,6 +84,7 @@ void loop() { else if (digitalRead(P2_BTN_UP) == LOW && current_gmode_idx > 0) { update_menu= true; current_gmode_idx -= 1; + game_mode= PVP; } // 1. P vs P @@ -94,12 +98,16 @@ void loop() { p1= &human_pad1; p2= &bot_pad2; mode_selected= true; + update_menu= false; + game_mode= PVC; } // 3. CPU vs CPU else if (digitalRead(P1_BTN_UP) == LOW || digitalRead(P1_BTN_BOTTOM) == LOW && game_modes(current_gmode_idx) == CVC) { p1= &bot_pad1; p2= &bot_pad2; mode_selected= true; + update_menu= false; + game_mode= CVC; } if (update_menu) { @@ -112,7 +120,36 @@ void loop() { else if (mode_selected) { engine.set_players(p1, p2); renderer.set_players(p1, p2); + if (game_mode == PVC || game_mode == CVC) { + game_status= MENU_BOT_SKILLS; + delay(300); // avoid accidental double click for next menu + } + else game_status= TIMER; + } + break; + } + + case MENU_BOT_SKILLS: { + if (digitalRead(P2_BTN_BOTTOM) == LOW && current_bot_menu_idx < sizeof(frame_bot_skills)/sizeof(frame_bot_skills[0]) -1) { + current_bot_menu_idx += 1; + update_menu_bot_skills= true; + } + else if (digitalRead(P2_BTN_UP) == LOW && current_bot_menu_idx > 0) { + current_bot_menu_idx -= 1; + update_menu_bot_skills= true; + } + else if (digitalRead(P1_BTN_UP) == LOW || digitalRead(P1_BTN_BOTTOM) == LOW) { + if (!p1 -> is_human()) p1 -> set_skills(current_bot_menu_idx + 1); + if (!p2 -> is_human()) p2 -> set_skills(current_bot_menu_idx + 1); game_status= TIMER; + update_menu_bot_skills= false; + } + + if (update_menu_bot_skills) { + const byte (*current_skill_frame)[12]= frame_bot_skills[current_bot_menu_idx]; + matrix.loadPixels((uint8_t*)current_skill_frame, MATRIX_HEIGHT * MATRIX_WIDTH); + update_menu= false; + delay(300); } break; } diff --git a/src/font.cpp b/src/font.cpp index e082bc8..6635fe0 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -212,3 +212,27 @@ const byte frame_cvc[MATRIX_HEIGHT][MATRIX_WIDTH] = { }; const byte (*frame_gmodes[3])[12]= {frame_pvp, frame_pvc, frame_cvc}; + +const byte frame_bot_skill_easy[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 }, + { 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0 }, + { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, + { 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0 }, + { 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0 }, + { 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +}; + +const byte frame_bot_skill_hard[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 }, + { 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0 }, + { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, + { 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0 }, + { 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0 }, + { 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +}; + +const byte (*frame_bot_skills[3])[12]= {frame_bot_skill_easy, frame_bot_skill_hard}; diff --git a/src/font.h b/src/font.h index a805269..8d593ec 100644 --- a/src/font.h +++ b/src/font.h @@ -13,4 +13,8 @@ extern const byte frame_pvc[MATRIX_HEIGHT][MATRIX_WIDTH]; extern const byte frame_cvc[MATRIX_HEIGHT][MATRIX_WIDTH]; extern const byte (*frame_gmodes[3])[12]; +extern const byte frame_bot_skill_easy[MATRIX_HEIGHT][MATRIX_WIDTH]; +extern const byte frame_bot_skill_hard[MATRIX_HEIGHT][MATRIX_WIDTH]; +extern const byte (*frame_bot_skills[3])[12]; + #endif diff --git a/src/paddle.cpp b/src/paddle.cpp index 30f7d98..0cbcbff 100644 --- a/src/paddle.cpp +++ b/src/paddle.cpp @@ -44,10 +44,14 @@ bool Paddle::check_pad_movement(Ball &ball) { // redefine me return false; } + uint8_t Paddle::get_skills() { return 0; } +void Paddle::set_skills(uint8_t skills) { +} + bool HumanPaddle::check_pad_movement() { bool need_refresh= false; if (digitalRead(_pin_btn_top) == LOW) { @@ -66,6 +70,8 @@ bool BotPaddle::check_pad_movement(Ball &ball) { int8_t ball_dir= ball.get_direction_x(); int8_t ball_dir_ver= ball.get_direction_y(); + uint8_t skills= this -> get_skills(); + // ball is moving left and pad is on right, do not move if (ball_dir < 0 && _pos_x > MATRIX_WIDTH / 2) return false; // ball is moving right and pad is on left, do not move @@ -74,18 +80,18 @@ bool BotPaddle::check_pad_movement(Ball &ball) { uint8_t ball_x= ball.get_x(); int8_t ball_distance= ball_x - _pos_x; if (ball_distance < 0) ball_distance *= -1; - switch (this -> get_skills()) { + switch (skills) { case 1: - if (ball_distance > 2) return false; + if (ball_distance > 3) return false; break; case 2: - if (ball_distance > 3) return false; + if (ball_distance > 4) return false; break; } - // TODO BotPaddle movement logics - // on higher difficult level i could also check the ball direction - // or at lover difficulty level i could also check the distance from the pad and move only when the ball si near + uint8_t move_chances= random(skills * 10) % 2; + if (!move_chances) return false; + enum Movement {NONE, UP, DOWN}; Movement _movment= NONE; @@ -113,3 +119,9 @@ bool BotPaddle::check_pad_movement(Ball &ball) { uint8_t BotPaddle::get_skills() { return _skills; } + +void BotPaddle::set_skills(uint8_t skills) { + if (skills < 0) _skills= 0; + else if (skills > 1) _skills= 1; + else _skills= skills; +} diff --git a/src/paddle.h b/src/paddle.h index e40f9b9..0b39be0 100644 --- a/src/paddle.h +++ b/src/paddle.h @@ -27,6 +27,7 @@ class Paddle { virtual bool check_pad_movement(); virtual bool check_pad_movement(Ball &ball); virtual uint8_t get_skills(); + virtual void set_skills(uint8_t skills); }; class HumanPaddle : public Paddle { @@ -46,13 +47,11 @@ class BotPaddle : public Paddle { uint8_t _skills; // this is the difficulty level public: - BotPaddle(uint8_t position, uint8_t pos_x, uint8_t skills) - : Paddle(position, false), _pos_x(pos_x), _skills(skills) { - if (_skills < 1) _skills= 1; - if (_skills > 2) _skills= 2; - } + BotPaddle(uint8_t position, uint8_t pos_x) + : Paddle(position, false), _pos_x(pos_x) {} bool check_pad_movement(Ball &ball); uint8_t get_skills(); + void set_skills(uint8_t skills); }; #endif