Make menu to state machine

This commit is contained in:
Vladislav Khorev committed 2026-03-06 21:52:00 +03:00
1 parent ac551122d9
commit 4af20c65e6
14 files changed
+480 -335

No files matched your search

+169 -286
View File
@@ -1,5 +1,5 @@
#include "MenuManager.h"
#include "MenuManager.h"
#include <iostream>
namespace ZL {
@@ -10,294 +10,177 @@ namespace ZL {
void MenuManager::setupMenu()
{
mainMenuRoot = loadUiFromFile("resources/config/main_menu.json", renderer, CONST_ZIP_FILE);
shipSelectionRoot = loadUiFromFile("resources/config/ship_selection_menu.json", renderer, CONST_ZIP_FILE);
gameplayRoot = loadUiFromFile("resources/config/ui.json", renderer, CONST_ZIP_FILE);
gameOverRoot = loadUiFromFile("resources/config/game_over.json", renderer, CONST_ZIP_FILE);
connectionLostRoot = loadUiFromFile("resources/config/connection_lost.json", renderer, CONST_ZIP_FILE);
uiManager.loadFromFile("resources/config/main_menu.json", renderer, CONST_ZIP_FILE);
uiSavedRoot = loadUiFromFile("resources/config/ui.json", renderer, CONST_ZIP_FILE);
settingsSavedRoot = loadUiFromFile("resources/config/settings.json", renderer, CONST_ZIP_FILE);
multiplayerSavedRoot = loadUiFromFile("resources/config/multiplayer_menu.json", renderer, CONST_ZIP_FILE);
gameOverSavedRoot = loadUiFromFile("resources/config/game_over.json", renderer, CONST_ZIP_FILE);
auto shipSelectionRoot = loadUiFromFile("resources/config/ship_selection_menu.json", renderer, CONST_ZIP_FILE);
std::function<void()> loadGameplayUI;
loadGameplayUI = [this]() {
uiManager.replaceRoot(uiSavedRoot);
auto velocityTv = uiManager.findTextView("velocityText");
if (velocityTv) {
velocityTv->rect.x = 10.0f;
velocityTv->rect.y = static_cast<float>(Environment::height) - velocityTv->rect.h - 10.0f;
}
else {
std::cerr << "Failed to find velocityText in UI" << std::endl;
}
uiManager.startAnimationOnNode("backgroundNode", "bgScroll");
static bool isExitButtonAnimating = false;
uiManager.setAnimationCallback("settingsButton", "buttonsExit", [this]() {
std::cerr << "Settings button animation finished -> ??????? ? ?????????" << std::endl;
if (uiManager.pushMenuFromSavedRoot(settingsSavedRoot)) {
uiManager.setButtonCallback("Opt1", [this](const std::string& n) {
std::cerr << "Opt1 pressed: " << n << std::endl;
});
uiManager.setButtonCallback("Opt2", [this](const std::string& n) {
std::cerr << "Opt2 pressed: " << n << std::endl;
});
uiManager.setButtonCallback("backButton", [this](const std::string& n) {
uiManager.stopAllAnimations();
uiManager.popMenu();
});
}
else {
std::cerr << "Failed to open settings menu after animations" << std::endl;
}
});
uiManager.setAnimationCallback("exitButton", "bgScroll", [this]() {
std::cerr << "Exit button bgScroll animation finished" << std::endl;
g_exitBgAnimating = false;
});
uiManager.setButtonCallback("playButton", [this](const std::string& name) {
std::cerr << "Play button pressed: " << name << std::endl;
});
uiManager.setButtonCallback("settingsButton", [this](const std::string& name) {
std::cerr << "Settings button pressed: " << name << std::endl;
uiManager.startAnimationOnNode("playButton", "buttonsExit");
uiManager.startAnimationOnNode("settingsButton", "buttonsExit");
uiManager.startAnimationOnNode("exitButton", "buttonsExit");
});
uiManager.setButtonCallback("exitButton", [this](const std::string& name) {
std::cerr << "Exit button pressed: " << name << std::endl;
if (!g_exitBgAnimating) {
std::cerr << "start repeat anim bgScroll on exitButton" << std::endl;
g_exitBgAnimating = true;
uiManager.startAnimationOnNode("exitButton", "bgScroll");
}
else {
std::cerr << "stop repeat anim bgScroll on exitButton" << std::endl;
g_exitBgAnimating = false;
uiManager.stopAnimationOnNode("exitButton", "bgScroll");
auto exitButton = uiManager.findButton("exitButton");
if (exitButton) {
exitButton->animOffsetX = 0.0f;
exitButton->animOffsetY = 0.0f;
exitButton->animScaleX = 1.0f;
exitButton->animScaleY = 1.0f;
exitButton->buildMesh();
}
}
});
uiManager.setButtonCallback("shootButton", [this](const std::string& name) {
onFirePressed();
});
uiManager.setButtonCallback("shootButton2", [this](const std::string& name) {
onFirePressed();
});
uiManager.setButtonCallback("plusButton", [this](const std::string& name) {
int newVel = Environment::shipState.selectedVelocity+1;
if (newVel > 4)
{
newVel = 4;
}
onVelocityChanged(newVel);
});
uiManager.setButtonCallback("minusButton", [this](const std::string& name) {
int newVel = Environment::shipState.selectedVelocity-1;
if (newVel < 0)
{
newVel = 0;
}
onVelocityChanged(newVel);
});
uiManager.setSliderCallback("velocitySlider", [this](const std::string& name, float value) {
int newVel = roundf(value * 10);
if (newVel > 2)
{
newVel = 2;
}
if (newVel != Environment::shipState.selectedVelocity) {
onVelocityChanged(newVel);
}
});
};
uiManager.setButtonCallback("singleButton", [this, shipSelectionRoot, loadGameplayUI](const std::string& name) {
std::cerr << "Single button pressed: " << name << " -> open ship selection UI\n";
if (!shipSelectionRoot) {
std::cerr << "Failed to load ship selection UI\n";
return;
}
if (uiManager.pushMenuFromSavedRoot(shipSelectionRoot)) {
uiManager.setButtonCallback("spaceshipButton", [this, loadGameplayUI](const std::string& btnName) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
int shipType = 0;
uiManager.popMenu();
loadGameplayUI();
if (onSingleplayerPressed) onSingleplayerPressed(nick, shipType);
});
uiManager.setButtonCallback("cargoshipButton", [this, loadGameplayUI](const std::string& btnName) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
int shipType = 1;
uiManager.popMenu();
loadGameplayUI();
if (onSingleplayerPressed) onSingleplayerPressed(nick, shipType);
});
uiManager.setButtonCallback("backButton", [this](const std::string& btnName) {
uiManager.popMenu();
});
}
else {
std::cerr << "Failed to push ship selection menu\n";
}
});
uiManager.setButtonCallback("multiplayerButton", [this, shipSelectionRoot, loadGameplayUI](const std::string& name) {
std::cerr << "Multiplayer button pressed: " << name << " -> open ship selection UI\n";
if (!shipSelectionRoot) {
std::cerr << "Failed to load ship selection UI\n";
return;
}
if (uiManager.pushMenuFromSavedRoot(shipSelectionRoot)) {
uiManager.setButtonCallback("spaceshipButton", [this, loadGameplayUI](const std::string& btnName) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
int shipType = 0;
uiManager.popMenu();
loadGameplayUI();
if (onMultiplayerPressed) onMultiplayerPressed(nick, shipType);
});
uiManager.setButtonCallback("cargoshipButton", [this, loadGameplayUI](const std::string& btnName) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
int shipType = 1;
uiManager.popMenu();
loadGameplayUI();
if (onMultiplayerPressed) onMultiplayerPressed(nick, shipType);
});
uiManager.setButtonCallback("backButton", [this](const std::string& btnName) {
uiManager.popMenu();
});
}
else {
std::cerr << "Failed to push ship selection menu\n";
}
});
/*uiManager.setButtonCallback("multiplayerButton2", [this, shipSelectionRoot, loadGameplayUI](const std::string& name) {
std::cerr << "Multiplayer button pressed → opening multiplayer menu\n";
uiManager.startAnimationOnNode("playButton", "buttonsExit");
uiManager.startAnimationOnNode("settingsButton", "buttonsExit");
uiManager.startAnimationOnNode("multiplayerButton", "buttonsExit");
uiManager.startAnimationOnNode("exitButton", "buttonsExit");
if (uiManager.pushMenuFromSavedRoot(multiplayerSavedRoot)) {
uiManager.setButtonCallback("connectButton", [this](const std::string& buttonName) {
std::string serverAddress = uiManager.getTextFieldValue("serverInputField");
if (serverAddress.empty()) {
uiManager.setText("statusText", "Please enter server address");
return;
}
uiManager.setText("statusText", "Connecting to " + serverAddress + "...");
std::cerr << "Connecting to server: " << serverAddress << std::endl;
});
uiManager.setButtonCallback("backButton", [this](const std::string& buttonName) {
uiManager.popMenu();
});
uiManager.setTextFieldCallback("serverInputField",
[this](const std::string& fieldName, const std::string& newText) {
std::cout << "Server input field changed to: " << newText << std::endl;
});
std::cerr << "Multiplayer menu loaded successfully\n";
}
else {
std::cerr << "Failed to load multiplayer menu\n";
}
std::cerr << "Single button pressed: " << name << " -> open ship selection UI\n";
if (!shipSelectionRoot) {
std::cerr << "Failed to load ship selection UI\n";
return;
}
if (uiManager.pushMenuFromSavedRoot(shipSelectionRoot)) {
uiManager.setButtonCallback("spaceshipButton", [this, loadGameplayUI](const std::string& btnName) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
int shipType = 0;
uiManager.popMenu();
loadGameplayUI();
if (onSingleplayerPressed) onSingleplayerPressed(nick, shipType);
});
uiManager.setButtonCallback("cargoshipButton", [this, loadGameplayUI](const std::string& btnName) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
int shipType = 1;
uiManager.popMenu();
loadGameplayUI();
if (onSingleplayerPressed) onSingleplayerPressed(nick, shipType);
});
uiManager.setButtonCallback("backButton", [this](const std::string& btnName) {
uiManager.popMenu();
});
}
else {
std::cerr << "Failed to push ship selection menu\n";
}
});
uiManager.setButtonCallback("exitButton", [](const std::string& name) {
std::cerr << "Exit from main menu pressed: " << name << " -> exiting\n";
Environment::exitGameLoop = true;
});*/
enterMainMenu();
}
bool MenuManager::shouldRenderSpace() const
{
return state == GameState::Gameplay
|| state == GameState::GameOver
|| state == GameState::ConnectionLost;
}
// ── State: MainMenu ──────────────────────────────────────────────────────
void MenuManager::enterMainMenu()
{
state = GameState::MainMenu;
uiManager.replaceRoot(mainMenuRoot);
uiManager.setButtonCallback("singleButton", [this](const std::string&) {
enterShipSelectionSingle();
});
uiManager.setButtonCallback("multiplayerButton", [this](const std::string&) {
enterShipSelectionMulti();
});
}
// ── State: ShipSelectionSingle ───────────────────────────────────────────
void MenuManager::enterShipSelectionSingle()
{
state = GameState::ShipSelectionSingle;
uiManager.replaceRoot(shipSelectionRoot);
uiManager.setButtonCallback("spaceshipButton", [this](const std::string&) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
enterGameplay();
if (onSingleplayerPressed) onSingleplayerPressed(nick, 0);
});
uiManager.setButtonCallback("cargoshipButton", [this](const std::string&) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
enterGameplay();
if (onSingleplayerPressed) onSingleplayerPressed(nick, 1);
});
uiManager.setButtonCallback("backButton", [this](const std::string&) {
enterMainMenu();
});
}
// ── State: ShipSelectionMulti ─────────────────────────────────────────────
void MenuManager::enterShipSelectionMulti()
{
state = GameState::ShipSelectionMulti;
uiManager.replaceRoot(shipSelectionRoot);
uiManager.setButtonCallback("spaceshipButton", [this](const std::string&) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
enterGameplay();
if (onMultiplayerPressed) onMultiplayerPressed(nick, 0);
});
uiManager.setButtonCallback("cargoshipButton", [this](const std::string&) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
enterGameplay();
if (onMultiplayerPressed) onMultiplayerPressed(nick, 1);
});
uiManager.setButtonCallback("backButton", [this](const std::string&) {
enterMainMenu();
});
}
// ── State: Gameplay ──────────────────────────────────────────────────────
void MenuManager::enterGameplay()
{
state = GameState::Gameplay;
uiManager.replaceRoot(gameplayRoot);
auto velocityTv = uiManager.findTextView("velocityText");
if (velocityTv) {
velocityTv->rect.x = 10.0f;
velocityTv->rect.y = static_cast<float>(Environment::height) - velocityTv->rect.h - 10.0f;
}
uiManager.startAnimationOnNode("backgroundNode", "bgScroll");
uiManager.setButtonCallback("shootButton", [this](const std::string&) {
if (onFirePressed) onFirePressed();
});
uiManager.setButtonCallback("shootButton2", [this](const std::string&) {
if (onFirePressed) onFirePressed();
});
uiManager.setButtonCallback("plusButton", [this](const std::string&) {
int newVel = Environment::shipState.selectedVelocity + 1;
if (newVel > 4) newVel = 4;
if (onVelocityChanged) onVelocityChanged(newVel);
});
uiManager.setButtonCallback("minusButton", [this](const std::string&) {
int newVel = Environment::shipState.selectedVelocity - 1;
if (newVel < 0) newVel = 0;
if (onVelocityChanged) onVelocityChanged(newVel);
});
uiManager.setSliderCallback("velocitySlider", [this](const std::string&, float value) {
int newVel = static_cast<int>(roundf(value * 10));
if (newVel > 2) newVel = 2;
if (newVel != Environment::shipState.selectedVelocity) {
if (onVelocityChanged) onVelocityChanged(newVel);
}
});
}
// ── State: GameOver ──────────────────────────────────────────────────────
void MenuManager::enterGameOver(int score)
{
state = GameState::GameOver;
uiManager.replaceRoot(gameOverRoot);
uiManager.setText("scoreText", "Score: " + std::to_string(score));
uiManager.setButtonCallback("restartButton", [this](const std::string&) {
if (onRestartPressed) onRestartPressed();
enterGameplay();
});
uiManager.setButtonCallback("gameOverExitButton", [this](const std::string&) {
Environment::exitGameLoop = true;
});
}
// ── State: ConnectionLost ─────────────────────────────────────────────────
void MenuManager::enterConnectionLost()
{
state = GameState::ConnectionLost;
uiManager.replaceRoot(connectionLostRoot);
uiManager.setButtonCallback("reconnectButton", [this](const std::string&) {
// TODO: reconnect logic
});
uiManager.setButtonCallback("exitServerButton", [this](const std::string&) {
Environment::exitGameLoop = true;
});
}
// ── Public event API ──────────────────────────────────────────────────────
void MenuManager::showGameOver(int score)
{
if (!uiGameOverShown) {
if (uiManager.pushMenuFromSavedRoot(gameOverSavedRoot)) {
uiManager.setText("scoreText", std::string("Score: ") + std::to_string(score));
uiManager.setButtonCallback("restartButton", [this](const std::string& name) {
uiManager.setText("scoreText", "");
uiGameOverShown = false;
uiManager.popMenu();
if (onRestartPressed) onRestartPressed();
});
uiManager.setButtonCallback("gameOverExitButton", [this](const std::string& name) {
Environment::exitGameLoop = true;
});
uiGameOverShown = true;
}
else {
std::cerr << "Failed to load game_over.json\n";
}
if (state == GameState::Gameplay) {
enterGameOver(score);
}
}
}
void MenuManager::showConnectionLost()
{
if (state == GameState::Gameplay) {
enterConnectionLost();
}
}
} // namespace ZL