diff --git a/include/common.h b/include/common.h index c05325e..7949b86 100644 --- a/include/common.h +++ b/include/common.h @@ -1,6 +1,6 @@ #pragma once -#include +#include template constexpr uint16_t arraySize(const T (&)[N]) { return N; } diff --git a/include/engine/system-config.h b/include/core/configuration.h similarity index 90% rename from include/engine/system-config.h rename to include/core/configuration.h index 80f83ea..779a71f 100644 --- a/include/engine/system-config.h +++ b/include/core/configuration.h @@ -2,9 +2,9 @@ #include -namespace Engine +namespace SystemCore { - struct SystemConfig + struct Configuration { // REQUIRED: modify this address to match the mac address of your PS3 controller static constexpr char macAddress[] = "00:1b:fb:8e:87:ac"; diff --git a/include/core/context-manager.h b/include/core/context-manager.h index a17b12f..acf2aec 100644 --- a/include/core/context-manager.h +++ b/include/core/context-manager.h @@ -2,12 +2,12 @@ #include "engine/layer.h" #include "engine/state-manager.h" -#include "engine/system-config.h" +#include "core/configuration.h" #include "player/controller.h" #include "lights/led-strip.h" #include "display/display.h" -namespace Core +namespace SystemCore { class ContextManager { @@ -19,7 +19,7 @@ namespace Core Engine::Layer *application = nullptr; Engine::StateManager stateManager; - Engine::SystemConfig config; + SystemCore::Configuration config; Player::Controller controller; Lights::LedStrip leds; Display::OledDisplay display; diff --git a/include/display/display-images.h b/include/display/display-images.h index f4fba66..8cd26ed 100644 --- a/include/display/display-images.h +++ b/include/display/display-images.h @@ -11,7 +11,7 @@ namespace Display { struct ImageInitLogo { - inline static const unsigned char rawValues[] PROGMEM = { + static constexpr unsigned char rawValues[] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, diff --git a/include/display/display.h b/include/display/display.h index 5f961bc..e54e38f 100644 --- a/include/display/display.h +++ b/include/display/display.h @@ -11,9 +11,9 @@ #include "display/display-images.h" -// forward declaration because of ContextManager/OledDisplay circular dependency -namespace Core +namespace SystemCore { + // forward declaration because of ContextManager/OledDisplay circular dependency class ContextManager; } @@ -23,7 +23,7 @@ namespace Display class OledDisplay { public: - OledDisplay(Core::ContextManager *contextManager); + OledDisplay(SystemCore::ContextManager *contextManager); void updateDisplay(); private: @@ -32,7 +32,7 @@ namespace Display static constexpr int DISPLAY_ADDRESS = 0x3c; Adafruit_SSD1306 display; - Core::ContextManager *contextManager; + SystemCore::ContextManager *contextManager; ImageInitLogo initLogo; char selectedOption(uint8_t index, uint8_t selectedOptionIndex) { return index == selectedOptionIndex ? '>' : ' '; }; diff --git a/include/engine/engine.h b/include/engine/engine.h index f4a97c5..634bf66 100644 --- a/include/engine/engine.h +++ b/include/engine/engine.h @@ -16,7 +16,7 @@ namespace Engine void standbyControllerConnection(); private: - Core::ContextManager contextManager; + SystemCore::ContextManager contextManager; uint32_t lastRender = 0; void initializeEngine(); void renderLedStrip(); diff --git a/include/engine/state-manager.h b/include/engine/state-manager.h index bdd7e5d..fa116d6 100644 --- a/include/engine/state-manager.h +++ b/include/engine/state-manager.h @@ -1,9 +1,9 @@ #pragma once -#include "games/recall/recall-state.h" -#include "games/phase-evasion/phase-evasion-state.h" -#include "games/demo/demo-state.h" -#include "scenes/canvas/canvas-state.h" +#include "games/recall/state.h" +#include "games/phase-evasion/state.h" +#include "games/demo/state.h" +#include "scenes/canvas/state.h" namespace Engine { @@ -76,11 +76,11 @@ namespace Engine const char *printGameName(uint8_t index); const char *printSceneName(uint8_t index); - Games::RecallGameState &getRecallGameState() { return recallGameState; } - Games::PhaseEvasionGameState &getPhaseEvasionGameState() { return phaseEvasionGameState; } - Games::DemoGameState &getDemoGameState() { return demoGameState; } + Games::Recall::GameState &getRecallGameState() { return recallGameState; } + Games::PhaseEvasion::GameState &getPhaseEvasionGameState() { return phaseEvasionGameState; } + Games::Demo::GameState &getDemoGameState() { return demoGameState; } - Scenes::CanvasSceneState &getCanvasSceneState() { return canvasSceneState; } + Scenes::Canvas::SceneState &getCanvasSceneState() { return canvasSceneState; } private: SystemState systemState = SystemState::MenuHome; @@ -89,10 +89,10 @@ namespace Engine GameSelection userGameChoice = GameSelection::Demo; SceneSelection userSceneChoice = SceneSelection::Canvas; - Games::RecallGameState recallGameState; - Games::PhaseEvasionGameState phaseEvasionGameState; - Games::DemoGameState demoGameState; + Games::Recall::GameState recallGameState; + Games::PhaseEvasion::GameState phaseEvasionGameState; + Games::Demo::GameState demoGameState; - Scenes::CanvasSceneState canvasSceneState; + Scenes::Canvas::SceneState canvasSceneState; }; } \ No newline at end of file diff --git a/include/games/demo/demo-core.h b/include/games/demo/controller.h similarity index 62% rename from include/games/demo/demo-core.h rename to include/games/demo/controller.h index b2b8414..c750e7e 100644 --- a/include/games/demo/demo-core.h +++ b/include/games/demo/controller.h @@ -2,14 +2,14 @@ #include "core/context-manager.h" #include "engine/layer.h" -#include "games/demo/demo-player.h" +#include "games/demo/player.h" -namespace Games +namespace Games::Demo { - class DemoCore : public Engine::Layer + class Controller : public Engine::Layer { public: - DemoCore(Core::ContextManager *ctx) : Engine::Layer{}, contextManager{ctx}, player1{DemoPlayer{ctx}}, player2{DemoPlayer{ctx}} + Controller(SystemCore::ContextManager *ctx) : Engine::Layer{}, contextManager{ctx}, player1{Player{ctx}}, player2{Player{ctx}} { contextManager->stateManager.getDemoGameState().reset(); } @@ -21,9 +21,9 @@ namespace Games void incrementHighScore(); private: - Core::ContextManager *contextManager; - DemoPlayer player1; - DemoPlayer player2; + SystemCore::ContextManager *contextManager; + Player player1; + Player player2; static constexpr float speed = 4.0f; }; } \ No newline at end of file diff --git a/include/games/demo/demo-player.h b/include/games/demo/player.h similarity index 52% rename from include/games/demo/demo-player.h rename to include/games/demo/player.h index fa8da66..a4f4252 100644 --- a/include/games/demo/demo-player.h +++ b/include/games/demo/player.h @@ -3,17 +3,17 @@ #include "core/context-manager.h" #include "player/player.h" -namespace Games +namespace Games::Demo { - class DemoPlayer : public Player::Player + class Player : public ::Player::Player { public: - DemoPlayer(Core::ContextManager *ctx) : contextManager{ctx}, Player::Player{ctx} {}; + Player(SystemCore::ContextManager *ctx) : contextManager{ctx}, ::Player::Player{ctx} {}; void updatePlayer1LedBuffer(); void updatePlayer2LedBuffer(); private: - Core::ContextManager *contextManager; + SystemCore::ContextManager *contextManager; static constexpr uint16_t width = 7; }; } \ No newline at end of file diff --git a/include/games/demo/demo-state.h b/include/games/demo/state.h similarity index 62% rename from include/games/demo/demo-state.h rename to include/games/demo/state.h index 5c95907..4c87d8d 100644 --- a/include/games/demo/demo-state.h +++ b/include/games/demo/state.h @@ -2,12 +2,12 @@ #include -namespace Games +namespace Games::Demo { - class DemoGameState + class GameState { public: - DemoGameState() : highScore{0}, currentScore{0} {} + GameState() : highScore{0}, currentScore{0} {} void reset() { highScore = currentScore = 0; } uint16_t highScore; uint16_t currentScore; diff --git a/include/games/phase-evasion/controller.h b/include/games/phase-evasion/controller.h new file mode 100644 index 0000000..083a9e6 --- /dev/null +++ b/include/games/phase-evasion/controller.h @@ -0,0 +1,31 @@ +#pragma once + +#include "engine/layer.h" +#include "engine/timer.h" +#include "core/context-manager.h" +#include "games/phase-evasion/player.h" +#include "games/phase-evasion/flare.h" +#include "games/phase-evasion/flare-manager.h" + +namespace Games::PhaseEvasion +{ + class Controller : public Engine::Layer, private Engine::Timer + { + public: + Controller(SystemCore::ContextManager *ctx); + void nextEvent() override; + static constexpr uint16_t playerClearance = 20; + + private: + SystemCore::ContextManager *contextManager; + GameState &state = contextManager->stateManager.getPhaseEvasionGameState(); + Player player; + FlareManager flareManager; + + void getUpdates(); + void renderUserColor(); + void renderFlare(); + void checkCollision(); + void checkGrowth(); + }; +} \ No newline at end of file diff --git a/include/games/phase-evasion/flare-manager.h b/include/games/phase-evasion/flare-manager.h new file mode 100644 index 0000000..e2db21f --- /dev/null +++ b/include/games/phase-evasion/flare-manager.h @@ -0,0 +1,30 @@ +#pragma once + +#include "games/phase-evasion/flare.h" + +namespace Games::PhaseEvasion +{ + class FlareManager : public Engine::Timer + { + public: + FlareManager() = default; + FlareManager(const FlareManager &) = delete; + FlareManager &operator=(const FlareManager &) = delete; + + Flare &operator[](uint16_t index) { return flarePool[index]; } + const Flare &operator[](uint16_t index) const { return flarePool[index]; } + + auto begin() { return flarePool.begin(); } + auto end() { return flarePool.end(); } + const auto begin() const { return flarePool.begin(); } + const auto end() const { return flarePool.end(); } + + const size_t size() const; + + void updatePositions(); + void dispatch(); + + private: + std::array flarePool; + }; +} \ No newline at end of file diff --git a/include/games/phase-evasion/flare.h b/include/games/phase-evasion/flare.h new file mode 100644 index 0000000..a5ddcfe --- /dev/null +++ b/include/games/phase-evasion/flare.h @@ -0,0 +1,36 @@ +#pragma once + +#include "esp_system.h" + +#include "common.h" + +#include "engine/timer.h" +#include "core/configuration.h" +#include "lights/color.h" + +namespace Games::PhaseEvasion +{ + class Flare : public Engine::Timer + { + public: + Flare() : active{false}, + color{Lights::Color::WhiteSmoke}, + speed{0.0f}, + positionFloat{SystemCore::Configuration::numLeds + width} {}; + + static constexpr uint16_t width = 10; + void updatePosition(); + uint16_t getPosition() const { return static_cast(positionFloat); } + + const Lights::Color getColor() const { return color; } + bool isActive() const { return active; } + void activate(Lights::Color color, float speed); + void deactivate(); + + private: + bool active; + Lights::Color color; + float speed; + float positionFloat; + }; +} \ No newline at end of file diff --git a/include/games/phase-evasion/phase-evasion-core.h b/include/games/phase-evasion/phase-evasion-core.h deleted file mode 100644 index 4982ec8..0000000 --- a/include/games/phase-evasion/phase-evasion-core.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "engine/layer.h" -#include "engine/timer.h" -#include "core/context-manager.h" -#include "games/phase-evasion/phase-evasion-player.h" - -namespace Games -{ - class PhaseEvasionCore : public Engine::Layer, private Engine::Timer - { - public: - PhaseEvasionCore(Core::ContextManager *ctx); - void nextEvent() override; - - private: - Core::ContextManager *contextManager; - PhaseEvasionPlayer player; - }; -} \ No newline at end of file diff --git a/include/games/phase-evasion/phase-evasion-flare.h b/include/games/phase-evasion/phase-evasion-flare.h deleted file mode 100644 index d0c787b..0000000 --- a/include/games/phase-evasion/phase-evasion-flare.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "lights/color-code.h" - -namespace Games -{ - class PhaseEvasionFlare - { - public: - PhaseEvasionFlare() - { - color = Lights::ColorCode::MenuLightBlue; - }; - - private: - Lights::ColorCode color; - }; -} \ No newline at end of file diff --git a/include/games/phase-evasion/phase-evasion-player.h b/include/games/phase-evasion/phase-evasion-player.h deleted file mode 100644 index 71cae00..0000000 --- a/include/games/phase-evasion/phase-evasion-player.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "core/context-manager.h" -#include "player/player.h" - -namespace Games -{ - class PhaseEvasionPlayer : public Player::Player - { - public: - PhaseEvasionPlayer(Core::ContextManager *ctx) : contextManager{ctx}, Player::Player{ctx} {}; - - private: - Core::ContextManager *contextManager; - static constexpr uint16_t width = 7; - }; -} \ No newline at end of file diff --git a/include/games/phase-evasion/phase-evasion-state.h b/include/games/phase-evasion/phase-evasion-state.h deleted file mode 100644 index 7fc2446..0000000 --- a/include/games/phase-evasion/phase-evasion-state.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -namespace Games -{ - class PhaseEvasionGameState - { - public: - PhaseEvasionGameState() : highScore{0}, spectersDodged{0} {} - void reset() { highScore = spectersDodged = 0; } - uint16_t highScore; - uint16_t spectersDodged; - }; -} \ No newline at end of file diff --git a/include/games/phase-evasion/player.h b/include/games/phase-evasion/player.h new file mode 100644 index 0000000..830fe91 --- /dev/null +++ b/include/games/phase-evasion/player.h @@ -0,0 +1,25 @@ +#pragma once + +#include "core/context-manager.h" +#include "player/player.h" + +namespace Games::PhaseEvasion +{ + class Player : public ::Player::Player + { + public: + Player(SystemCore::ContextManager *ctx) : contextManager{ctx}, ::Player::Player{ctx} {}; + void checkColorChangeRequest(); + Lights::Color getColor() { return currentColor; } + static constexpr uint16_t width = 10; + + private: + SystemCore::ContextManager *contextManager; + Lights::Color currentColor; + static constexpr ::Player::ControllerButton availableGameplayButtons[] = { + ::Player::ControllerButton::Cross, + ::Player::ControllerButton::Square, + ::Player::ControllerButton::Triangle, + ::Player::ControllerButton::Circle}; + }; +} \ No newline at end of file diff --git a/include/games/phase-evasion/state.h b/include/games/phase-evasion/state.h new file mode 100644 index 0000000..4c9778c --- /dev/null +++ b/include/games/phase-evasion/state.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +namespace Games::PhaseEvasion +{ + enum class Actions + { + Startup, + ActiveGame, + GameOver + }; + + class GameState + { + public: + GameState() : highScore{0}, spectersDodged{0} {} + uint16_t highScore; + uint16_t spectersDodged; + Actions current = Actions::Startup; + void reset() { highScore = spectersDodged = 0; } + }; +} \ No newline at end of file diff --git a/include/games/recall/recall-core.h b/include/games/recall/controller.h similarity index 70% rename from include/games/recall/recall-core.h rename to include/games/recall/controller.h index dcfb984..81c4777 100644 --- a/include/games/recall/recall-core.h +++ b/include/games/recall/controller.h @@ -6,17 +6,17 @@ #include "lights/color.h" #include "lights/color-code.h" -namespace Games +namespace Games::Recall { - class RecallCore : public Engine::Layer, private Engine::Timer + class Controller : public Engine::Layer, private Engine::Timer { public: - RecallCore(Core::ContextManager *ctx); + Controller(SystemCore::ContextManager *ctx); void nextEvent() override; private: - Core::ContextManager *contextManager; - RecallGameState &state = contextManager->stateManager.getRecallGameState(); + SystemCore::ContextManager *contextManager; + GameState &state = contextManager->stateManager.getRecallGameState(); uint16_t gameplaySpeedIlluminated = 500; uint16_t gameplaySpeedPaused = gameplaySpeedIlluminated / 6; @@ -27,11 +27,6 @@ namespace Games Player::ControllerButton::Triangle, Player::ControllerButton::Circle}; uint16_t sequenceIndex = 0; - Lights::Color colorPalette[4] = { - {Lights::ColorCode::GameBlue}, // ✕ blue - {Lights::ColorCode::GameRed}, // ◯ red - {Lights::ColorCode::GameGreen}, // △ green - {Lights::ColorCode::GameYellow}}; // □ yellow Player::ControllerButton gameplayColors[maxRound]; float gameOverLedPhaseShift = 0.0f; float successFadeawayAnimation = 1.0f; diff --git a/include/games/recall/recall-state.h b/include/games/recall/state.h similarity index 65% rename from include/games/recall/recall-state.h rename to include/games/recall/state.h index 3602a56..8155674 100644 --- a/include/games/recall/recall-state.h +++ b/include/games/recall/state.h @@ -2,9 +2,9 @@ #include -namespace Games +namespace Games::Recall { - enum class GameState + enum class Actions { Startup, ComputerPlaybackOnDisplay, @@ -14,13 +14,13 @@ namespace Games GameOver }; - class RecallGameState + class GameState { public: - RecallGameState() : highScore{0}, round{0} {} + GameState() : highScore{0}, round{0} {} uint16_t highScore; uint16_t round; - GameState current = GameState::Startup; + Actions current = Actions::Startup; void reset() { highScore = round = 0; } }; diff --git a/include/lights/color.h b/include/lights/color.h index c1585b2..8a6a52a 100644 --- a/include/lights/color.h +++ b/include/lights/color.h @@ -15,7 +15,7 @@ namespace Lights Color(uint8_t red, uint8_t green, uint8_t blue) : CRGB(red, green, blue) {} Color(ColorCode color) : CRGB{static_cast(color)} {} - Lights::Color operator*(double scale) const + Color operator*(double scale) const { Color result; result.r = static_cast(std::clamp(r * scale, 0.0, 255.0)); @@ -24,7 +24,7 @@ namespace Lights return result; } - Lights::Color operator*(uint8_t scale) const + Color operator*(uint8_t scale) const { Color result; result.r = (r * scale) / 255; @@ -33,7 +33,7 @@ namespace Lights return result; } - Lights::Color operator/(double scale) const + Color operator/(double scale) const { Color result; result.r = static_cast(std::clamp(r / scale, 0.0, 255.0)); @@ -42,7 +42,7 @@ namespace Lights return result; } - Lights::Color operator/(uint8_t scale) const + Color operator/(uint8_t scale) const { Color result; result.r = (r / scale) / 255; @@ -51,7 +51,7 @@ namespace Lights return result; } - Lights::Color &operator*=(double scale) + Color &operator*=(double scale) { r = static_cast(std::clamp(r * scale, 0.0, 255.0)); g = static_cast(std::clamp(g * scale, 0.0, 255.0)); @@ -59,4 +59,10 @@ namespace Lights return *this; } }; + + inline const Color colorPalette[4] = { + Color(ColorCode::GameBlue), + Color(ColorCode::GameRed), + Color(ColorCode::GameGreen), + Color(ColorCode::GameYellow)}; } \ No newline at end of file diff --git a/include/lights/led-luminance.h b/include/lights/led-luminance.h index fabdfdd..d10a4b1 100644 --- a/include/lights/led-luminance.h +++ b/include/lights/led-luminance.h @@ -1,13 +1,13 @@ #pragma once -#include "engine/system-config.h" +#include "core/configuration.h" namespace Lights { class LedLuminance { public: - LedLuminance(Engine::SystemConfig &configuration) : config{configuration} {} + LedLuminance(SystemCore::Configuration &configuration) : config{configuration} {} static constexpr float MAX_LED_BRIGHTNESS = 255.0f; static constexpr int MAX_ADC_READING = 4095; @@ -17,7 +17,7 @@ namespace Lights static uint8_t applyGamma(uint8_t value); private: - const Engine::SystemConfig &config; + const SystemCore::Configuration &config; int currentLuminance = MAX_ADC_READING; }; } \ No newline at end of file diff --git a/include/lights/led-strip.h b/include/lights/led-strip.h index c5a650c..c7dadcd 100644 --- a/include/lights/led-strip.h +++ b/include/lights/led-strip.h @@ -1,6 +1,6 @@ #pragma once -#include "engine/system-config.h" +#include "core/configuration.h" #include "lights/color.h" #include "lights/led-buffer.h" #include "lights/led-luminance.h" @@ -11,15 +11,15 @@ namespace Lights { public: LedBuffer buffer; - LedStrip(Engine::SystemConfig &configuration); + LedStrip(SystemCore::Configuration &configuration); Color *getRawColors(); - static constexpr uint16_t size() { return Engine::SystemConfig::numLeds; } + static constexpr uint16_t size() { return SystemCore::Configuration::numLeds; } void reset(); void adjustLuminance(); private: - const Engine::SystemConfig &config; + const SystemCore::Configuration &config; LedLuminance luminance; }; } \ No newline at end of file diff --git a/include/player/player.h b/include/player/player.h index decd206..6ded16e 100644 --- a/include/player/player.h +++ b/include/player/player.h @@ -7,12 +7,12 @@ namespace Player class Player { public: - Player(Core::ContextManager *ctx) : contextManager{ctx} {}; + Player(SystemCore::ContextManager *ctx) : contextManager{ctx} {}; void move(const int distance, const float speed); uint16_t getPosition() { return position; } protected: - Core::ContextManager *contextManager; + SystemCore::ContextManager *contextManager; uint16_t position = 0; float positionPrecise = 0.0f; }; diff --git a/include/scenes/canvas/canvas.h b/include/scenes/canvas/canvas.h deleted file mode 100644 index d9e0a70..0000000 --- a/include/scenes/canvas/canvas.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "core/context-manager.h" -#include "engine/timer.h" -#include "lights/color-hsl.h" - -namespace Scenes -{ - class Canvas : public Engine::Layer, private Engine::Timer - { - public: - Canvas(Core::ContextManager *ctx); - void nextEvent() override; - - private: - Core::ContextManager *contextManager; - CanvasSceneState &state = contextManager->stateManager.getCanvasSceneState(); - Lights::ColorHsl colorHsl; - bool hasChange = false; - bool controllerWasActive = false; - - inline void checkAnalogColorChange(); - inline void checkBalanceColorRequest(); - inline void checkNewColorRequest(); - inline void checkStableControllerForDisplay(); - inline void checkChangeOccured(); - inline void reset(); - }; -} \ No newline at end of file diff --git a/include/scenes/canvas/controller.h b/include/scenes/canvas/controller.h new file mode 100644 index 0000000..d62998f --- /dev/null +++ b/include/scenes/canvas/controller.h @@ -0,0 +1,29 @@ +#pragma once + +#include "core/context-manager.h" +#include "engine/timer.h" +#include "lights/color-hsl.h" + +namespace Scenes::Canvas +{ + class Controller : public Engine::Layer, private Engine::Timer + { + public: + Controller(SystemCore::ContextManager *ctx); + void nextEvent() override; + + private: + SystemCore::ContextManager *contextManager; + SceneState &state = contextManager->stateManager.getCanvasSceneState(); + Lights::ColorHsl colorHsl; + bool hasChange = false; + bool controllerWasActive = false; + + void checkAnalogColorChange(); + void checkBalanceColorRequest(); + void checkNewColorRequest(); + void checkStableControllerForDisplay(); + void checkChangeOccured(); + void reset(); + }; +} \ No newline at end of file diff --git a/include/scenes/canvas/canvas-state.h b/include/scenes/canvas/state.h similarity index 57% rename from include/scenes/canvas/canvas-state.h rename to include/scenes/canvas/state.h index 096c192..9d9fd8a 100644 --- a/include/scenes/canvas/canvas-state.h +++ b/include/scenes/canvas/state.h @@ -4,12 +4,12 @@ #include "lights/color.h" -namespace Scenes +namespace Scenes::Canvas { - class CanvasSceneState + class SceneState { public: - CanvasSceneState() : currentColor{} {} + SceneState() : currentColor{} {} Lights::Color currentColor; }; } \ No newline at end of file diff --git a/src/core/context-manager.cpp b/src/core/context-manager.cpp index bd88e73..422fdc5 100644 --- a/src/core/context-manager.cpp +++ b/src/core/context-manager.cpp @@ -1,11 +1,11 @@ #include "core/context-manager.h" -#include "games/demo/demo-core.h" -#include "games/recall/recall-core.h" -#include "games/phase-evasion/phase-evasion-core.h" -#include "scenes/canvas/canvas.h" +#include "games/demo/controller.h" +#include "games/recall/controller.h" +#include "games/phase-evasion/controller.h" +#include "scenes/canvas/controller.h" #include "logger.h" -namespace Core +namespace SystemCore { ContextManager::ContextManager() : leds{config}, display{this} {} @@ -150,19 +150,19 @@ namespace Core switch (stateManager.current()) { case Engine::SystemState::GameRecall: - application = new Games::RecallCore{this}; + application = new Games::Recall::Controller{this}; logf("Transitioning to Recall (Game)"); break; case Engine::SystemState::GamePhaseEvasion: - application = new Games::PhaseEvasionCore{this}; + application = new Games::PhaseEvasion::Controller{this}; logf("Transitioning to Phase Evasion (Game)"); break; case Engine::SystemState::GameDemo: - application = new Games::DemoCore{this}; + application = new Games::Demo::Controller{this}; logf("Transitioning to Demo (Game)"); break; case Engine::SystemState::SceneCanvas: - application = new Scenes::Canvas{this}; + application = new Scenes::Canvas::Controller{this}; logf("Transitioning to Canvas (Scene)"); break; } diff --git a/src/display/display.cpp b/src/display/display.cpp index c4a2a69..59a53b3 100644 --- a/src/display/display.cpp +++ b/src/display/display.cpp @@ -5,7 +5,7 @@ namespace Display { - OledDisplay::OledDisplay(Core::ContextManager *ctx) : contextManager{ctx} + OledDisplay::OledDisplay(SystemCore::ContextManager *ctx) : contextManager{ctx} { Wire.begin(); display.begin(SSD1306_SWITCHCAPVCC, DISPLAY_ADDRESS); diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 6f248af..7044a89 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -110,6 +110,7 @@ namespace Engine lastRender = micros(); log("Startup process completed. Transitioning to Main Menu"); } + randomSeed(esp_random()); } void GameEngine::standbyControllerConnection() @@ -206,7 +207,7 @@ namespace Engine void GameEngine::displayTask(void *param) { - auto *ctx = static_cast(param); + auto *ctx = static_cast(param); while (true) { if (ctx->stateManager.displayShouldUpdate) diff --git a/src/games/demo/demo-core.cpp b/src/games/demo/core.cpp similarity index 75% rename from src/games/demo/demo-core.cpp rename to src/games/demo/core.cpp index 93c6853..b5ffe14 100644 --- a/src/games/demo/demo-core.cpp +++ b/src/games/demo/core.cpp @@ -1,12 +1,12 @@ -#include "games/demo/demo-core.h" +#include "games/demo/controller.h" #include "player/controller.h" #include "logger.h" -namespace Games +namespace Games::Demo { - void DemoCore::nextEvent() + void Controller::nextEvent() { - if (contextManager->controller.wasPressed(Player::ControllerButton::Cross)) + if (contextManager->controller.wasPressed(::Player::ControllerButton::Cross)) { incrementCurrentScore(); contextManager->stateManager.displayShouldUpdate = true; @@ -20,13 +20,13 @@ namespace Games player2.updatePlayer2LedBuffer(); } - void DemoCore::incrementCurrentScore() + void Controller::incrementCurrentScore() { ++contextManager->stateManager.getDemoGameState().currentScore; contextManager->stateManager.displayShouldUpdate = true; } - void DemoCore::incrementHighScore() + void Controller::incrementHighScore() { ++contextManager->stateManager.getDemoGameState().highScore; contextManager->stateManager.displayShouldUpdate = true; diff --git a/src/games/demo/demo-player.cpp b/src/games/demo/player.cpp similarity index 89% rename from src/games/demo/demo-player.cpp rename to src/games/demo/player.cpp index 8bcf014..645df10 100644 --- a/src/games/demo/demo-player.cpp +++ b/src/games/demo/player.cpp @@ -1,11 +1,11 @@ #include #include -#include "games/demo/demo-player.h" +#include "games/demo/player.h" -namespace Games +namespace Games::Demo { - void DemoPlayer::updatePlayer1LedBuffer() + void Player::updatePlayer1LedBuffer() { float center = (width + 1) / 2.0f; for (uint16_t i = 1; i <= width; ++i) @@ -21,7 +21,7 @@ namespace Games } } - void DemoPlayer::updatePlayer2LedBuffer() + void Player::updatePlayer2LedBuffer() { float center = (width + 1) / 2.0f; diff --git a/src/games/phase-evasion/controller.cpp b/src/games/phase-evasion/controller.cpp new file mode 100644 index 0000000..66ddbfe --- /dev/null +++ b/src/games/phase-evasion/controller.cpp @@ -0,0 +1,100 @@ +#include "games/phase-evasion/controller.h" +#include "logger.h" + +namespace Games::PhaseEvasion +{ + Controller::Controller(SystemCore::ContextManager *ctx) : contextManager{ctx}, + player{ctx} + { + state = contextManager->stateManager.getPhaseEvasionGameState(); + state.reset(); + state.current = Actions::Startup; + wait(500); + } + + void Controller::nextEvent() + { + switch (state.current) + { + case Actions::Startup: + if (isReady()) + { + state.current = Actions::ActiveGame; + flareManager.dispatch(); + log("Starting new game."); + wait(1000); + } + break; + case Actions::ActiveGame: + getUpdates(); + checkGrowth(); + checkCollision(); + renderFlare(); + renderUserColor(); + break; + case Actions::GameOver: + for (uint16_t i = 0; i < contextManager->config.numLeds; ++i) + { + contextManager->leds.buffer[i] = Lights::ColorCode::GameRed; + } + break; + } + } + + void Controller::getUpdates() + { + player.checkColorChangeRequest(); + flareManager.updatePositions(); + } + + void Controller::renderUserColor() + { + for (uint16_t i = playerClearance; i < playerClearance + player.width; ++i) + { + contextManager->leds.buffer[i] = player.getColor(); + } + } + + void Controller::renderFlare() + { + for (const auto &flare : flareManager) + { + if (!flare.isActive()) + continue; + + uint16_t start = std::max(flare.getPosition() - flare.width, 0); + uint16_t end = std::min(flare.getPosition(), contextManager->config.numLeds); + + for (uint16_t i = start; i < end; ++i) + { + contextManager->leds.buffer[i] = flare.getColor(); + } + } + } + + void Controller::checkCollision() + { + for (const auto &flare : flareManager) + { + if (!flare.isActive()) + continue; + + uint16_t start = std::max(flare.getPosition() - flare.width, 0); + uint16_t end = std::min(flare.getPosition(), contextManager->config.numLeds); + + if (start <= playerClearance + player.width && end >= playerClearance && player.getColor() != flare.getColor()) + { + state.current = Actions::GameOver; + } + } + } + + void Controller::checkGrowth() + { + if (isReady()) + { + flareManager.dispatch(); + wait(1000); + } + } +} \ No newline at end of file diff --git a/src/games/phase-evasion/flare-manager.cpp b/src/games/phase-evasion/flare-manager.cpp new file mode 100644 index 0000000..b30a3a4 --- /dev/null +++ b/src/games/phase-evasion/flare-manager.cpp @@ -0,0 +1,39 @@ +#include "games/phase-evasion/flare-manager.h" +#include "common.h" +#include "logger.h" + +namespace Games::PhaseEvasion +{ + void FlareManager::dispatch() + { + auto flare = flarePool.begin(); + while (flare != flarePool.end()) + { + if (!flare->isActive()) + { + uint16_t colorIndex = static_cast(esp_random()) % arraySize(Lights::colorPalette); + flare->activate(Lights::colorPalette[colorIndex], 0.75); + return; + } + ++flare; + } + logf("Flare dispatch: no free flares"); + } + + void FlareManager::updatePositions() + { + for (auto &flare : flarePool) + { + if (!flare.isActive()) + continue; + + flare.updatePosition(); + } + } + + const size_t FlareManager::size() const + { + return std::count_if(flarePool.begin(), flarePool.end(), [](const Flare &flare) + { return flare.isActive(); }); + } +} \ No newline at end of file diff --git a/src/games/phase-evasion/flare.cpp b/src/games/phase-evasion/flare.cpp new file mode 100644 index 0000000..8dae6a2 --- /dev/null +++ b/src/games/phase-evasion/flare.cpp @@ -0,0 +1,30 @@ +#include "games/phase-evasion/flare.h" + +namespace Games::PhaseEvasion +{ + void Flare::updatePosition() + { + if (positionFloat <= 0.0f) + { + active = false; + color = Lights::Color::WhiteSmoke; + } + else + { + positionFloat -= speed; + } + } + + void Flare::activate(Lights::Color _color, float _speed) + { + active = true; + color = _color; + speed = _speed; + positionFloat = static_cast(SystemCore::Configuration::numLeds + width); + } + + void Flare::deactivate() + { + active = false; + } +} \ No newline at end of file diff --git a/src/games/phase-evasion/phase-evasion-core.cpp b/src/games/phase-evasion/phase-evasion-core.cpp deleted file mode 100644 index fe86d11..0000000 --- a/src/games/phase-evasion/phase-evasion-core.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "games/phase-evasion/phase-evasion-core.h" - -namespace Games -{ - PhaseEvasionCore::PhaseEvasionCore(Core::ContextManager *ctx) : contextManager{ctx}, player{PhaseEvasionPlayer{contextManager}} - { - contextManager->stateManager.getPhaseEvasionGameState().reset(); - } - - void PhaseEvasionCore::nextEvent() - { - } -} \ No newline at end of file diff --git a/src/games/phase-evasion/player.cpp b/src/games/phase-evasion/player.cpp new file mode 100644 index 0000000..6ee4599 --- /dev/null +++ b/src/games/phase-evasion/player.cpp @@ -0,0 +1,29 @@ +#include "games/phase-evasion/player.h" +#include "logger.h" + +namespace Games::PhaseEvasion +{ + void Player::checkColorChangeRequest() + { + for (auto button : availableGameplayButtons) + { + if (contextManager->controller.isDown(button)) + { +#ifdef DEBUG + if (currentColor != Lights::colorPalette[static_cast(button)]) + { + auto c = Lights::colorPalette[static_cast(button)]; + logf("User pressed color=%u (%u - %u - %u)", button, c.r, c.g, c.b); + } +#endif + currentColor = Lights::colorPalette[static_cast(button)]; + return; + } + } + if (currentColor != Lights::Color::DimGray) + { + log("User returned color to neutral."); + currentColor = Lights::Color::DimGray; + } + } +} \ No newline at end of file diff --git a/src/games/recall/recall-core.cpp b/src/games/recall/controller.cpp similarity index 78% rename from src/games/recall/recall-core.cpp rename to src/games/recall/controller.cpp index 82a9fff..55b16ed 100644 --- a/src/games/recall/recall-core.cpp +++ b/src/games/recall/controller.cpp @@ -1,21 +1,21 @@ #include "esp_system.h" -#include "games/recall/recall-core.h" +#include "games/recall/controller.h" #include "common.h" #include "logger.h" -namespace Games +namespace Games::Recall { - RecallCore::RecallCore(Core::ContextManager *ctx) : contextManager{ctx} + Controller::Controller(SystemCore::ContextManager *ctx) : contextManager{ctx} { setupGameColors(); state = contextManager->stateManager.getRecallGameState(); state.reset(); - state.current = GameState::Startup; + state.current = Actions::Startup; wait(gameplaySpeedIlluminated); } - void RecallCore::setupGameColors() + void Controller::setupGameColors() { for (uint16_t i = 0; i < maxRound; ++i) { @@ -26,42 +26,42 @@ namespace Games gameplayColors[i] = static_cast(colorIndex); } auto button = gameplayColors[0]; - auto &color = colorPalette[static_cast(button)]; + auto &color = Lights::colorPalette[static_cast(button)]; log("First round's RGB color:"); logf(" Color=%u (%u - %u - %u)", button, color.r, color.g, color.b); } - void RecallCore::nextEvent() + void Controller::nextEvent() { handleUserSpeedChange(); switch (state.current) { - case GameState::Startup: + case Actions::Startup: if (isReady()) { - state.current = GameState::ComputerPlaybackOnDisplay; + state.current = Actions::ComputerPlaybackOnDisplay; wait(gameplaySpeedIlluminated); } break; - case GameState::ComputerPlaybackOnDisplay: + case Actions::ComputerPlaybackOnDisplay: displayComputerPlayback(); break; - case GameState::ComputerPlaybackPaused: + case Actions::ComputerPlaybackPaused: pauseComputerPlayback(); break; - case GameState::PlayerResponseEvaluation: + case Actions::PlayerResponseEvaluation: evaluateUserRecall(); break; - case GameState::PlayerResponseVerified: + case Actions::PlayerResponseVerified: prepareComputerPlayback(); break; - case GameState::GameOver: + case Actions::GameOver: gameOver(); break; } } - void RecallCore::handleUserSpeedChange() + void Controller::handleUserSpeedChange() { if (contextManager->controller.wasPressed(Player::ControllerButton::Up) || contextManager->controller.leftAnalog().y < -64) { @@ -77,11 +77,11 @@ namespace Games } } - void RecallCore::displayComputerPlayback() + void Controller::displayComputerPlayback() { if (isReady()) { - state.current = GameState::ComputerPlaybackPaused; + state.current = Actions::ComputerPlaybackPaused; wait(gameplaySpeedPaused); return; } @@ -99,16 +99,16 @@ namespace Games { double x = static_cast(i); double scope = std::exp(-0.5 * std::pow((x - mu) / delta, 2.0)); - auto color = colorPalette[static_cast(gameplayColors[sequenceIndex])]; + auto color = Lights::colorPalette[static_cast(gameplayColors[sequenceIndex])]; contextManager->leds.buffer[i] = color * scope; } } - void RecallCore::pauseComputerPlayback() + void Controller::pauseComputerPlayback() { if (sequenceIndex >= state.round) { - state.current = GameState::PlayerResponseEvaluation; + state.current = Actions::PlayerResponseEvaluation; sequenceIndex = 0; contextManager->controller.reset(); successFadeawayAnimation = 1; @@ -119,16 +119,16 @@ namespace Games if (isReady()) { ++sequenceIndex; - state.current = GameState::ComputerPlaybackOnDisplay; + state.current = Actions::ComputerPlaybackOnDisplay; wait(gameplaySpeedIlluminated); } } - void RecallCore::evaluateUserRecall() + void Controller::evaluateUserRecall() { if (sequenceIndex > state.round && isReady()) { - state.current = GameState::PlayerResponseVerified; + state.current = Actions::PlayerResponseVerified; ++state.round; contextManager->stateManager.displayShouldUpdate = true; contextManager->controller.reset(); @@ -140,7 +140,7 @@ namespace Games evaluateUserButton(gameplayColors[sequenceIndex]); } - void RecallCore::evaluateUserButton(Player::ControllerButton expectedButton) + void Controller::evaluateUserButton(Player::ControllerButton expectedButton) { for (auto button : availableGameplayButtons) { @@ -149,19 +149,19 @@ namespace Games if (button == expectedButton) { ++sequenceIndex; - auto &color = colorPalette[static_cast(button)]; + auto &color = Lights::colorPalette[static_cast(button)]; logf("User correctly responded with color=%u (%u - %u - %u)", button, color.r, color.g, color.b); wait(gameplaySpeedPaused); return; } logf("User provided the incorrect answer. Entering game over sequence."); - state.current = GameState::GameOver; + state.current = Actions::GameOver; } } } - void RecallCore::illuminateOnSelection() + void Controller::illuminateOnSelection() { static uint32_t lastLightTime = 0; static int pressedButtonIndex = -1; @@ -185,12 +185,12 @@ namespace Games { auto boundaries = directionBoundaries(static_cast(pressedButtonIndex)); for (uint16_t i = boundaries.first; i <= boundaries.second; ++i) - contextManager->leds.buffer[i] = colorPalette[pressedButtonIndex]; + contextManager->leds.buffer[i] = Lights::colorPalette[pressedButtonIndex]; } } } - std::pair RecallCore::directionBoundaries(Player::ControllerButton button) + std::pair Controller::directionBoundaries(Player::ControllerButton button) { const auto &boundary = contextManager->config.recallBoundaries; @@ -209,7 +209,7 @@ namespace Games } } - void RecallCore::prepareComputerPlayback() + void Controller::prepareComputerPlayback() { if (isReady()) { @@ -217,10 +217,10 @@ namespace Games for (int i = 0; i <= sequenceIndex; ++i) { auto button = gameplayColors[i]; - auto &color = colorPalette[static_cast(button)]; + auto &color = Lights::colorPalette[static_cast(button)]; logf(" Color=%u (%u - %u - %u)", button, color.r, color.g, color.b); } - state.current = GameState::ComputerPlaybackOnDisplay; + state.current = Actions::ComputerPlaybackOnDisplay; sequenceIndex = 0; wait(gameplaySpeedIlluminated); return; @@ -229,17 +229,17 @@ namespace Games auto boundaries = directionBoundaries(gameplayColors[sequenceIndex - 1]); for (uint16_t i = boundaries.first; i <= boundaries.second; ++i) { - auto &color = colorPalette[static_cast(gameplayColors[sequenceIndex - 1])]; + auto &color = Lights::colorPalette[static_cast(gameplayColors[sequenceIndex - 1])]; contextManager->leds.buffer[i] = color * successFadeawayAnimation; } successFadeawayAnimation = std::clamp(successFadeawayAnimation - 0.08, 0.0, 1.0); } - void RecallCore::gameOver() + void Controller::gameOver() { if (contextManager->controller.wasPressed(Player::ControllerButton::Start)) { - state.current = GameState::Startup; + state.current = Actions::Startup; sequenceIndex = 0; state.reset(); contextManager->stateManager.getRecallGameState().reset(); diff --git a/src/lights/led-strip.cpp b/src/lights/led-strip.cpp index 7b7fbd2..f07fd62 100644 --- a/src/lights/led-strip.cpp +++ b/src/lights/led-strip.cpp @@ -2,9 +2,9 @@ namespace Lights { - LedStrip::LedStrip(Engine::SystemConfig &configuration) : config{configuration}, - buffer{configuration.numLeds}, - luminance{configuration} + LedStrip::LedStrip(SystemCore::Configuration &configuration) : config{configuration}, + buffer{configuration.numLeds}, + luminance{configuration} { #ifdef RELEASE FastLED.addLeds(static_cast(buffer), size()); diff --git a/src/player/player.cpp b/src/player/player.cpp index 1b8b6ee..eab4260 100644 --- a/src/player/player.cpp +++ b/src/player/player.cpp @@ -16,6 +16,6 @@ namespace Player if (positionPrecise < 0.0f) positionPrecise += ledCountF; - position = static_cast(std::floor(positionPrecise)) % static_cast(contextManager->leds.size()); + position = static_cast(std::floor(positionPrecise)) % contextManager->leds.size(); } } \ No newline at end of file diff --git a/src/scenes/canvas/canvas.cpp b/src/scenes/canvas/controller.cpp similarity index 88% rename from src/scenes/canvas/canvas.cpp rename to src/scenes/canvas/controller.cpp index 33a2f09..cdce2a7 100644 --- a/src/scenes/canvas/canvas.cpp +++ b/src/scenes/canvas/controller.cpp @@ -1,17 +1,17 @@ -#include "scenes/canvas/canvas.h" +#include "scenes/canvas/controller.h" #include "esp_system.h" #include "logger.h" #include -namespace Scenes +namespace Scenes::Canvas { - Canvas::Canvas(Core::ContextManager *ctx) : contextManager{ctx} + Controller::Controller(SystemCore::ContextManager *ctx) : contextManager{ctx} { reset(); } - void Canvas::nextEvent() + void Controller::nextEvent() { checkAnalogColorChange(); checkBalanceColorRequest(); @@ -25,7 +25,7 @@ namespace Scenes } } - void Canvas::checkAnalogColorChange() + void Controller::checkAnalogColorChange() { if (contextManager->controller.leftAnalog().x > 64) { @@ -59,7 +59,7 @@ namespace Scenes } } - void Canvas::checkNewColorRequest() + void Controller::checkNewColorRequest() { if (contextManager->controller.wasPressed(Player::ControllerButton::Triangle)) { @@ -68,7 +68,7 @@ namespace Scenes } } - void Canvas::checkBalanceColorRequest() + void Controller::checkBalanceColorRequest() { if (contextManager->controller.wasPressed(Player::ControllerButton::L1)) { @@ -91,7 +91,7 @@ namespace Scenes } } - void Canvas::checkChangeOccured() + void Controller::checkChangeOccured() { if (hasChange) { @@ -102,7 +102,7 @@ namespace Scenes } } - void Canvas::checkStableControllerForDisplay() + void Controller::checkStableControllerForDisplay() { bool isMoving = abs(contextManager->controller.leftAnalog().x) > 64 || @@ -122,7 +122,7 @@ namespace Scenes } } - void Canvas::reset() + void Controller::reset() { colorHsl.hue = static_cast(esp_random() % std::numeric_limits::max()); colorHsl.saturation = static_cast((esp_random() % 64u) + 191u);