From bb0f584bf6d68a3ad76ea78c68ed4869ec80e20e Mon Sep 17 00:00:00 2001 From: Vladislav Khorev Date: Sun, 1 Mar 2026 21:22:57 +0300 Subject: [PATCH] Working on UI and web game --- resources/Cargo_Base_color_sRGB.png | 4 +- resources/MainCharacter_Base_color_sRGB.png | 4 +- resources/config/game_over.json | 174 ++++++------- resources/config/game_over_old.json | 93 +++++++ resources/config/main_menu.json | 22 -- resources/config/ship_selection_menu.json | 119 +++++---- resources/config/ui.json | 239 ++++-------------- resources/config/ui_old.json | 194 ++++++++++++++ resources/multiplayer_menu/ship_cargo.png | 3 + .../multiplayer_menu/ship_cargo_pressed.png | 3 + resources/multiplayer_menu/ship_fighter.png | 3 + .../multiplayer_menu/ship_fighter_pressed.png | 3 + src/MenuManager.cpp | 10 +- src/UiManager.cpp | 61 ++++- src/UiManager.h | 16 +- 15 files changed, 566 insertions(+), 382 deletions(-) create mode 100644 resources/config/game_over_old.json create mode 100644 resources/config/ui_old.json create mode 100644 resources/multiplayer_menu/ship_cargo.png create mode 100644 resources/multiplayer_menu/ship_cargo_pressed.png create mode 100644 resources/multiplayer_menu/ship_fighter.png create mode 100644 resources/multiplayer_menu/ship_fighter_pressed.png diff --git a/resources/Cargo_Base_color_sRGB.png b/resources/Cargo_Base_color_sRGB.png index 58aee2f..493514c 100644 --- a/resources/Cargo_Base_color_sRGB.png +++ b/resources/Cargo_Base_color_sRGB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:88a34dad270df316707d8492823653a4c3143ee948f6c3fcdca232fa3f27a184 -size 2577457 +oid sha256:d8505521fa1598d9140e518deabcc7c20b226b90a7758e1b1ff5795c9a3b73a5 +size 2890059 diff --git a/resources/MainCharacter_Base_color_sRGB.png b/resources/MainCharacter_Base_color_sRGB.png index ba3e58c..9c074e3 100644 --- a/resources/MainCharacter_Base_color_sRGB.png +++ b/resources/MainCharacter_Base_color_sRGB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6e49da5723497cd4bf152d5f3fd99608f597f2dc3646c05fb478507f36b89697 -size 1669304 +oid sha256:69a783d983e5356aa0559f0f333ed6a083d4e5c9cd6190bf68a28d122af66ec8 +size 2823280 diff --git a/resources/config/game_over.json b/resources/config/game_over.json index 4fcac9d..6248579 100644 --- a/resources/config/game_over.json +++ b/resources/config/game_over.json @@ -1,93 +1,85 @@ { - "root": { - "type": "LinearLayout", - "orientation": "vertical", - "align": "center", - "x": 0, - "y": 0, - "width": 1920, - "height": 1080, - "background": { - "color": [0, 0, 0, 0.7] - }, - "children": [ - { - "type": "Button", - "name": "gameOverText", - "x": 476.5, - "y": 500, - "width": 327, - "height": 26, - "textures": { - "normal": "resources/game_over/MissionFailed.png", - "hover": "resources/game_over/MissionFailed.png", - "pressed": "resources/game_over/MissionFailed.png" - } - }, - { - "type": "Button", - "name": "underlineBtn", - "x": 556, - "y": 465, - "width": 168, - "height": 44, - "textures": { - "normal": "resources/game_over/Container.png", - "hover": "resources/game_over/Container.png", - "pressed": "resources/game_over/Container.png" - } - }, - { - "type": "Button", - "name": "finalscore", - "x": 596.5, - "y": 436, - "width": 87, - "height": 9, - "textures": { - "normal": "resources/game_over/FinalScore.png", - "hover": "resources/game_over/FinalScore.png", - "pressed": "resources/game_over/FinalScore.png" - } - }, - { - "type": "TextView", - "name": "scoreText", - "x": 350, - "y": 356, - "width": 600, - "height": 80, - "text": "0", - "fontSize": 36, - "color": [0, 217, 255, 1], - "align": "center" - }, - { - "type": "Button", - "name": "restartButton", - "x": 449, - "y": 308, - "width": 382, - "height": 56, - "textures": { - "normal": "resources/game_over/Filledbuttons.png", - "hover": "resources/game_over/Filledbuttons.png", - "pressed": "resources/game_over/Filledbuttons.png" - } - }, - { - "type": "Button", - "name": "gameOverExitButton", - "x": 449, - "y": 240, - "width": 382, - "height": 56, - "textures": { - "normal": "resources/game_over/Secondarybutton.png", - "hover": "resources/game_over/Secondarybutton.png", - "pressed": "resources/game_over/Secondarybutton.png" - } - } - ] - } + "root": { + "type": "LinearLayout", + "orientation": "vertical", + "vertical_align": "center", + "horizontal_align": "center", + "spacing": 10, + "x": 0, + "y": 0, + "width": "match_parent", + "height": "match_parent", + "children": [ + { + "type": "Button", + "name": "gameOverText", + "width": 327, + "height": 26, + "textures": { + "normal": "resources/game_over/MissionFailed.png", + "hover": "resources/game_over/MissionFailed.png", + "pressed": "resources/game_over/MissionFailed.png" + } + }, + { + "type": "Button", + "name": "underlineBtn", + "width": 168, + "height": 44, + "textures": { + "normal": "resources/game_over/Container.png", + "hover": "resources/game_over/Container.png", + "pressed": "resources/game_over/Container.png" + } + }, + { + "type": "Button", + "name": "finalscore", + "width": 87, + "height": 9, + "textures": { + "normal": "resources/game_over/FinalScore.png", + "hover": "resources/game_over/FinalScore.png", + "pressed": "resources/game_over/FinalScore.png" + } + }, + { + "type": "TextView", + "name": "scoreText", + "width": 600, + "height": 80, + "text": "0", + "fontSize": 36, + "color": [ + 0, + 217, + 255, + 1 + ], + "align": "center" + }, + { + "type": "Button", + "name": "restartButton", + "width": 382, + "height": 56, + "textures": { + "normal": "resources/game_over/Filledbuttons.png", + "hover": "resources/game_over/Filledbuttons.png", + "pressed": "resources/game_over/Filledbuttons.png" + } + }, + { + "type": "Button", + "name": "gameOverExitButton", + "width": 382, + "height": 56, + "textures": { + "normal": "resources/game_over/Secondarybutton.png", + "hover": "resources/game_over/Secondarybutton.png", + "pressed": "resources/game_over/Secondarybutton.png" + } + } + ] + } } \ No newline at end of file diff --git a/resources/config/game_over_old.json b/resources/config/game_over_old.json new file mode 100644 index 0000000..4fcac9d --- /dev/null +++ b/resources/config/game_over_old.json @@ -0,0 +1,93 @@ +{ + "root": { + "type": "LinearLayout", + "orientation": "vertical", + "align": "center", + "x": 0, + "y": 0, + "width": 1920, + "height": 1080, + "background": { + "color": [0, 0, 0, 0.7] + }, + "children": [ + { + "type": "Button", + "name": "gameOverText", + "x": 476.5, + "y": 500, + "width": 327, + "height": 26, + "textures": { + "normal": "resources/game_over/MissionFailed.png", + "hover": "resources/game_over/MissionFailed.png", + "pressed": "resources/game_over/MissionFailed.png" + } + }, + { + "type": "Button", + "name": "underlineBtn", + "x": 556, + "y": 465, + "width": 168, + "height": 44, + "textures": { + "normal": "resources/game_over/Container.png", + "hover": "resources/game_over/Container.png", + "pressed": "resources/game_over/Container.png" + } + }, + { + "type": "Button", + "name": "finalscore", + "x": 596.5, + "y": 436, + "width": 87, + "height": 9, + "textures": { + "normal": "resources/game_over/FinalScore.png", + "hover": "resources/game_over/FinalScore.png", + "pressed": "resources/game_over/FinalScore.png" + } + }, + { + "type": "TextView", + "name": "scoreText", + "x": 350, + "y": 356, + "width": 600, + "height": 80, + "text": "0", + "fontSize": 36, + "color": [0, 217, 255, 1], + "align": "center" + }, + { + "type": "Button", + "name": "restartButton", + "x": 449, + "y": 308, + "width": 382, + "height": 56, + "textures": { + "normal": "resources/game_over/Filledbuttons.png", + "hover": "resources/game_over/Filledbuttons.png", + "pressed": "resources/game_over/Filledbuttons.png" + } + }, + { + "type": "Button", + "name": "gameOverExitButton", + "x": 449, + "y": 240, + "width": 382, + "height": 56, + "textures": { + "normal": "resources/game_over/Secondarybutton.png", + "hover": "resources/game_over/Secondarybutton.png", + "pressed": "resources/game_over/Secondarybutton.png" + } + } + ] + } +} \ No newline at end of file diff --git a/resources/config/main_menu.json b/resources/config/main_menu.json index 129d810..55bbb1f 100644 --- a/resources/config/main_menu.json +++ b/resources/config/main_menu.json @@ -65,28 +65,6 @@ "pressed": "resources/main_menu/multi.png" } }, - { - "type": "Button", - "name": "multiplayerButton2", - "width": 382, - "height": 56, - "textures": { - "normal": "resources/main_menu/multi.png", - "hover": "resources/main_menu/multi.png", - "pressed": "resources/main_menu/multi.png" - } - }, - { - "type": "Button", - "name": "exitButton", - "width": 382, - "height": 56, - "textures": { - "normal": "resources/main_menu/exit.png", - "hover": "resources/main_menu/exit.png", - "pressed": "resources/main_menu/exit.png" - } - }, { "type": "Button", "name": "versionLabel", diff --git a/resources/config/ship_selection_menu.json b/resources/config/ship_selection_menu.json index 7d953fe..1a305de 100644 --- a/resources/config/ship_selection_menu.json +++ b/resources/config/ship_selection_menu.json @@ -1,64 +1,59 @@ { - "root": { - "name": "shipSelectionRoot", - "type": "node", - "children": [ - - { - "type": "TextField", - "name": "nicknameInput", - "x": 400, - "y": 150, - "width": 400, - "height": 50, - "placeholder": "Enter your nickname", - "fontPath": "resources/fonts/DroidSans.ttf", - "fontSize": 16, - "maxLength": 256, - "color": [122, 156, 198, 1], - "placeholderColor": [122, 156, 198, 1], - "backgroundColor": [15, 29, 51, 1], - "borderColor": [15, 29, 51, 1] - }, - { - "type": "Button", - "name": "spaceshipButton", - "x": 300, - "y": 320, - "width": 200, - "height": 80, - "textures": { - "normal": "resources/multiplayer_menu/JoinServer.png", - "hover": "resources/multiplayer_menu/JoinServer.png", - "pressed": "resources/multiplayer_menu/JoinServer.png" + "root": { + "type": "LinearLayout", + "orientation": "vertical", + "vertical_align": "center", + "horizontal_align": "center", + "spacing": 10, + "x": 0, + "y": 0, + "width": "match_parent", + "height": "match_parent", + "children": [ + { + "type": "LinearLayout", + "orientation": "horizontal", + "vertical_align": "center", + "horizontal_align": "center", + "spacing": 10, + "width": "match_parent", + "height": 260, + "children": [ + { + "type": "Button", + "name": "spaceshipButton", + "width": 256, + "height": 256, + "textures": { + "normal": "resources/multiplayer_menu/ship_fighter.png", + "hover": "resources/multiplayer_menu/ship_fighter_pressed.png", + "pressed": "resources/multiplayer_menu/ship_fighter_pressed.png" + } + }, + { + "type": "Button", + "name": "cargoshipButton", + "width": 256, + "height": 256, + "textures": { + "normal": "resources/multiplayer_menu/ship_cargo.png", + "hover": "resources/multiplayer_menu/ship_cargo_pressed.png", + "pressed": "resources/multiplayer_menu/ship_cargo_pressed.png" + } + } + ] + }, + { + "type": "Button", + "name": "backButton", + "width": 382, + "height": 56, + "textures": { + "normal": "resources/multiplayer_menu/Backbutton.png", + "hover": "resources/multiplayer_menu/Backbutton.png", + "pressed": "resources/multiplayer_menu/Backbutton.png" + } } - }, - { - "type": "Button", - "name": "cargoshipButton", - "x": 700, - "y": 320, - "width": 200, - "height": 80, - "textures": { - "normal": "resources/multiplayer_menu/JoinServer.png", - "hover": "resources/multiplayer_menu/JoinServer.png", - "pressed": "resources/multiplayer_menu/JoinServer.png" - } - }, - { - "type": "Button", - "name": "backButton", - "x": 449, - "y": 280, - "width": 382, - "height": 56, - "textures": { - "normal": "resources/multiplayer_menu/Backbutton.png", - "hover": "resources/multiplayer_menu/Backbutton.png", - "pressed": "resources/multiplayer_menu/Backbutton.png" - } - } - ] - } - } \ No newline at end of file + ] + } +} \ No newline at end of file diff --git a/resources/config/ui.json b/resources/config/ui.json index f8f1f7d..fa27292 100644 --- a/resources/config/ui.json +++ b/resources/config/ui.json @@ -1,194 +1,57 @@ { "root": { - "type": "FrameLayout", - "x": 0, - "y": 0, - "width": 1280, - "height": 720, - "children": [ - { - "type": "FrameLayout", - "name": "leftPanel", - "x": 100, - "y": 100, - "width": 320, - "height": 400, - "children": [ + "type": "FrameLayout", + "x": 0, + "y": 0, + "width": "match_parent", + "height": "match_parent", + "children": [ { - "type": "LinearLayout", - "name": "mainButtons", - "orientation": "vertical", - "spacing": 10, - "x": 0, - "y": 0, - "width": 300, - "height": 300, - "children": [ - { - "type": "Button", - "name": "playButton", - "x": -1000, - "y": 500, - "width": 200, - "height": 50, - "animations": { - "buttonsExit": { - "repeat": false, - "steps": [ - { - "type": "move", - "to": [ - -400, - 0 - ], - "duration": 1.0, - "easing": "easein" - } - ] - } - }, - "textures": { - "normal": "./resources/sand2.png", - "hover": "./resources/sand2.png", - "pressed": "./resources/sand2.png" - } - }, - { - "type": "Button", - "name": "settingsButton", - "x": -1000, - "y": 400, - "width": 200, - "height": 50, - "animations": { - "buttonsExit": { - "repeat": false, - "steps": [ - { - "type": "wait", - "duration": 0.5 - }, - { - "type": "move", - "to": [ - -400, - 0 - ], - "duration": 1.0, - "easing": "easein" - } - ] - } - }, - "textures": { - "normal": "./resources/sand2.png", - "hover": "./resources/sand2.png", - "pressed": "./resources/sand2.png" - } - }, - { - "type": "Button", - "name": "exitButton", - "x": -1000, - "y": 300, - "width": 200, - "height": 50, - "animations": { - "buttonsExit": { - "repeat": false, - "steps": [ - { - "type": "wait", - "duration": 1.0 - }, - { - "type": "move", - "to": [ - -400, - 0 - ], - "duration": 1.0, - "easing": "easein" - } - ] - }, - "bgScroll": { - "repeat": true, - "steps": [ - { - "type": "move", - "to": [ - 1280, - 0 - ], - "duration": 5.0, - "easing": "linear" - } - ] - } - }, - "textures": { - "normal": "./resources/sand2.png", - "hover": "./resources/sand2.png", - "pressed": "./resources/sand2.png" - } + "type": "Button", + "name": "shootButton", + "x": 0, + "y": 0, + "width": 150, + "height": 150, + "horizontal_gravity": "right", + "vertical_gravity": "bottom", + "textures": { + "normal": "resources/shoot_normal.png", + "hover": "resources/shoot_hover.png", + "pressed": "resources/shoot_pressed.png" + } + }, + { + "type": "Button", + "name": "shootButton2", + "x": 0, + "y": 0, + "width": 150, + "height": 150, + "horizontal_gravity": "left", + "vertical_gravity": "bottom", + "textures": { + "normal": "resources/shoot_normal.png", + "hover": "resources/shoot_hover.png", + "pressed": "resources/shoot_pressed.png" + } + }, + { + "type": "Slider", + "name": "velocitySlider", + "x": 10, + "y": 200, + "width": 80, + "height": 300, + "value": 0.0, + "orientation": "vertical", + "horizontal_gravity": "right", + "vertical_gravity": "bottom", + "textures": { + "track": "resources/velocitySliderTexture.png", + "knob": "resources/velocitySliderButton.png" } - ] } - ] - }, - { - "type": "Slider", - "name": "velocitySlider", - "x": 1140, - "y": 300, - "width": 50, - "height": 300, - "value": 0.0, - "orientation": "vertical", - "textures": { - "track": "resources/velocitySliderTexture.png", - "knob": "resources/velocitySliderButton.png" - } - }, - { - "type": "Button", - "name": "shootButton", - "x": 100, - "y": 100, - "width": 100, - "height": 100, - "textures": { - "normal": "resources/shoot_normal.png", - "hover": "resources/shoot_hover.png", - "pressed": "resources/shoot_pressed.png" - } - }, - { - "type": "Button", - "name": "shootButton2", - "x": 1000, - "y": 100, - "width": 100, - "height": 100, - "textures": { - "normal": "resources/shoot_normal.png", - "hover": "resources/shoot_hover.png", - "pressed": "resources/shoot_pressed.png" - } - }, - { - "type": "TextView", - "name": "velocityText", - "x": 10, - "y": 10, - "width": 200, - "height": 40, - "text": "Velocity: 0", - "fontSize": 24, - "color": [1.0, 1.0, 1.0, 1.0], - "centered": false - } - ] + ] } - } \ No newline at end of file +} \ No newline at end of file diff --git a/resources/config/ui_old.json b/resources/config/ui_old.json new file mode 100644 index 0000000..f8f1f7d --- /dev/null +++ b/resources/config/ui_old.json @@ -0,0 +1,194 @@ +{ + "root": { + "type": "FrameLayout", + "x": 0, + "y": 0, + "width": 1280, + "height": 720, + "children": [ + { + "type": "FrameLayout", + "name": "leftPanel", + "x": 100, + "y": 100, + "width": 320, + "height": 400, + "children": [ + { + "type": "LinearLayout", + "name": "mainButtons", + "orientation": "vertical", + "spacing": 10, + "x": 0, + "y": 0, + "width": 300, + "height": 300, + "children": [ + { + "type": "Button", + "name": "playButton", + "x": -1000, + "y": 500, + "width": 200, + "height": 50, + "animations": { + "buttonsExit": { + "repeat": false, + "steps": [ + { + "type": "move", + "to": [ + -400, + 0 + ], + "duration": 1.0, + "easing": "easein" + } + ] + } + }, + "textures": { + "normal": "./resources/sand2.png", + "hover": "./resources/sand2.png", + "pressed": "./resources/sand2.png" + } + }, + { + "type": "Button", + "name": "settingsButton", + "x": -1000, + "y": 400, + "width": 200, + "height": 50, + "animations": { + "buttonsExit": { + "repeat": false, + "steps": [ + { + "type": "wait", + "duration": 0.5 + }, + { + "type": "move", + "to": [ + -400, + 0 + ], + "duration": 1.0, + "easing": "easein" + } + ] + } + }, + "textures": { + "normal": "./resources/sand2.png", + "hover": "./resources/sand2.png", + "pressed": "./resources/sand2.png" + } + }, + { + "type": "Button", + "name": "exitButton", + "x": -1000, + "y": 300, + "width": 200, + "height": 50, + "animations": { + "buttonsExit": { + "repeat": false, + "steps": [ + { + "type": "wait", + "duration": 1.0 + }, + { + "type": "move", + "to": [ + -400, + 0 + ], + "duration": 1.0, + "easing": "easein" + } + ] + }, + "bgScroll": { + "repeat": true, + "steps": [ + { + "type": "move", + "to": [ + 1280, + 0 + ], + "duration": 5.0, + "easing": "linear" + } + ] + } + }, + "textures": { + "normal": "./resources/sand2.png", + "hover": "./resources/sand2.png", + "pressed": "./resources/sand2.png" + } + } + ] + } + ] + }, + { + "type": "Slider", + "name": "velocitySlider", + "x": 1140, + "y": 300, + "width": 50, + "height": 300, + "value": 0.0, + "orientation": "vertical", + "textures": { + "track": "resources/velocitySliderTexture.png", + "knob": "resources/velocitySliderButton.png" + } + }, + { + "type": "Button", + "name": "shootButton", + "x": 100, + "y": 100, + "width": 100, + "height": 100, + "textures": { + "normal": "resources/shoot_normal.png", + "hover": "resources/shoot_hover.png", + "pressed": "resources/shoot_pressed.png" + } + }, + { + "type": "Button", + "name": "shootButton2", + "x": 1000, + "y": 100, + "width": 100, + "height": 100, + "textures": { + "normal": "resources/shoot_normal.png", + "hover": "resources/shoot_hover.png", + "pressed": "resources/shoot_pressed.png" + } + }, + { + "type": "TextView", + "name": "velocityText", + "x": 10, + "y": 10, + "width": 200, + "height": 40, + "text": "Velocity: 0", + "fontSize": 24, + "color": [1.0, 1.0, 1.0, 1.0], + "centered": false + } + ] + } + } \ No newline at end of file diff --git a/resources/multiplayer_menu/ship_cargo.png b/resources/multiplayer_menu/ship_cargo.png new file mode 100644 index 0000000..88a6f68 --- /dev/null +++ b/resources/multiplayer_menu/ship_cargo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c86eb962f4abf04aacf7ebbf07433611e9afed42b0f7806fc892ae4a81b45b58 +size 13296 diff --git a/resources/multiplayer_menu/ship_cargo_pressed.png b/resources/multiplayer_menu/ship_cargo_pressed.png new file mode 100644 index 0000000..30590cf --- /dev/null +++ b/resources/multiplayer_menu/ship_cargo_pressed.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:97d66a6cd037fd75d6f78e72d37b14362683a0de38557470806db53d5e5675d9 +size 13694 diff --git a/resources/multiplayer_menu/ship_fighter.png b/resources/multiplayer_menu/ship_fighter.png new file mode 100644 index 0000000..4c6ea5f --- /dev/null +++ b/resources/multiplayer_menu/ship_fighter.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:072bf292acb2760e1ce0ab6c783eca114614d95a9451ba3c86088eee9d824b43 +size 29780 diff --git a/resources/multiplayer_menu/ship_fighter_pressed.png b/resources/multiplayer_menu/ship_fighter_pressed.png new file mode 100644 index 0000000..c0628eb --- /dev/null +++ b/resources/multiplayer_menu/ship_fighter_pressed.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d7a120a716261b122f6a90a04d7a9bbf1c9582e8c9c114e633bc348c15f7d002 +size 29926 diff --git a/src/MenuManager.cpp b/src/MenuManager.cpp index b87a72e..c5b072d 100644 --- a/src/MenuManager.cpp +++ b/src/MenuManager.cpp @@ -96,6 +96,7 @@ namespace ZL { } }); + uiManager.setButtonCallback("shootButton", [this](const std::string& name) { onFirePressed(); }); @@ -103,6 +104,7 @@ namespace ZL { onFirePressed(); }); uiManager.setSliderCallback("velocitySlider", [this](const std::string& name, float value) { + int newVel = roundf(value * 10); if (newVel > 2) { @@ -183,8 +185,8 @@ namespace ZL { } }); - uiManager.setButtonCallback("multiplayerButton2", [this, shipSelectionRoot, loadGameplayUI](const std::string& name) { - /*std::cerr << "Multiplayer button pressed → opening multiplayer 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"); @@ -219,7 +221,7 @@ namespace ZL { } 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"; @@ -255,7 +257,7 @@ namespace ZL { uiManager.setButtonCallback("exitButton", [](const std::string& name) { std::cerr << "Exit from main menu pressed: " << name << " -> exiting\n"; Environment::exitGameLoop = true; - }); + });*/ } void MenuManager::showGameOver(int score) diff --git a/src/UiManager.cpp b/src/UiManager.cpp index d063248..f06e47f 100644 --- a/src/UiManager.cpp +++ b/src/UiManager.cpp @@ -244,6 +244,20 @@ namespace ZL { if (valign == "center") node->layoutSettings.vAlign = VerticalAlign::Center; else if (valign == "bottom") node->layoutSettings.vAlign = VerticalAlign::Bottom; } + + if (j.contains("horizontal_gravity")) { + std::string hg = j["horizontal_gravity"].get(); + if (hg == "right") node->layoutSettings.hGravity = HorizontalGravity::Right; + else node->layoutSettings.hGravity = HorizontalGravity::Left; + } + + // Читаем Vertical Gravity + if (j.contains("vertical_gravity")) { + std::string vg = j["vertical_gravity"].get(); + if (vg == "bottom") node->layoutSettings.vGravity = VerticalGravity::Bottom; + else node->layoutSettings.vGravity = VerticalGravity::Top; + } + // Подготавливаем базовый rect для компонентов (кнопок и т.д.) // На этапе парсинга мы даем им "желаемый" размер UiRect initialRect = { node->localX, node->localY, node->width, node->height }; @@ -462,7 +476,14 @@ namespace ZL { void UiManager::replaceRoot(std::shared_ptr newRoot) { root = newRoot; - layoutNode(root, 0, 0, Environment::projectionWidth, Environment::projectionHeight); + layoutNode( + root, + 0.0f, 0.0f, // parentX, parentY (экран начинается с 0,0) + Environment::projectionWidth, // parentW + Environment::projectionHeight, // parentH + root->localX, // finalLocalX + root->localY // finalLocalY + ); buttons.clear(); sliders.clear(); textViews.clear(); @@ -487,15 +508,15 @@ namespace ZL { } - void UiManager::layoutNode(const std::shared_ptr& node, float parentX, float parentY, float parentW, float parentH) { + void UiManager::layoutNode(const std::shared_ptr& node, float parentX, float parentY, float parentW, float parentH, float finalLocalX, float finalLocalY) { + node->screenRect.w = (node->width < 0) ? parentW : node->width; node->screenRect.h = (node->height < 0) ? parentH : node->height; - // 2. Позиция относительно родителя - node->screenRect.x = parentX + node->localX; - node->screenRect.y = parentY + node->localY; + // ТЕПЕРЬ используем переданные координаты, а не node->localX напрямую + node->screenRect.x = parentX + finalLocalX; + node->screenRect.y = parentY + finalLocalY; - // Используем удобные локальные переменные для расчетов детей float currentW = node->screenRect.w; float currentH = node->screenRect.h; @@ -579,13 +600,26 @@ namespace ZL { // Сдвигаем курсор вправо для следующего элемента cursorX += childW + node->spacing; } - layoutNode(child, node->screenRect.x, node->screenRect.y, currentW, currentH); + layoutNode(child, node->screenRect.x, node->screenRect.y, currentW, currentH, child->localX, child->localY); } } else { - // Если Frame, просто идем по детям с их фиксированными координатами for (auto& child : node->children) { - layoutNode(child, node->screenRect.x, node->screenRect.y, node->width, node->height); + float childW = (child->width < 0) ? currentW : child->width; + float childH = (child->height < 0) ? currentH : child->height; + + float fLX = child->localX; + float fLY = child->localY; + + if (child->layoutSettings.hGravity == HorizontalGravity::Right) { + fLX = currentW - childW - child->localX; + } + if (child->layoutSettings.vGravity == VerticalGravity::Top) { + fLY = currentH - childH - child->localY; + } + + // Передаем рассчитанные fLX, fLY в рекурсию + layoutNode(child, node->screenRect.x, node->screenRect.y, currentW, currentH, fLX, fLY); } } @@ -629,7 +663,14 @@ namespace ZL { if (!root) return; // Запускаем расчет от корня, передавая размеры экрана как "родительские" - layoutNode(root, 0, 0, Environment::projectionWidth, Environment::projectionHeight); + layoutNode( + root, + 0.0f, 0.0f, // parentX, parentY (экран начинается с 0,0) + Environment::projectionWidth, // parentW + Environment::projectionHeight, // parentH + root->localX, // finalLocalX + root->localY // finalLocalY + ); } void UiManager::collectButtonsAndSliders(const std::shared_ptr& node) { diff --git a/src/UiManager.h b/src/UiManager.h index 0d2a704..59743d2 100644 --- a/src/UiManager.h +++ b/src/UiManager.h @@ -53,10 +53,24 @@ namespace ZL { Bottom }; + enum class HorizontalGravity { + Left, + Right + }; + + enum class VerticalGravity { + Bottom, // Обычно в OpenGL Y растет вверх, так что низ - это 0 + Top + }; + + // В структуру или класс, отвечающий за LinearLayout (вероятно, это свойства UiNode) struct LayoutSettings { HorizontalAlign hAlign = HorizontalAlign::Left; VerticalAlign vAlign = VerticalAlign::Top; + + HorizontalGravity hGravity = HorizontalGravity::Left; + VerticalGravity vGravity = VerticalGravity::Top; }; struct UiButton { @@ -248,7 +262,7 @@ namespace ZL { void updateAllLayouts(); private: - void layoutNode(const std::shared_ptr& node, float parentX, float parentY, float parentW, float parentH); + void layoutNode(const std::shared_ptr& node, float parentX, float parentY, float parentW, float parentH, float finalLocalX, float finalLocalY); void syncComponentRects(const std::shared_ptr& node); void collectButtonsAndSliders(const std::shared_ptr& node);