|
1 | 1 | #include "core/scenes/credits_scene.hpp" |
2 | 2 | #include "core/game.h" |
| 3 | +#include "ui/ui_theme.h" |
3 | 4 | #include <raylib.h> |
4 | 5 |
|
| 6 | +import engine; |
| 7 | + |
5 | 8 | namespace towerforge::core { |
6 | 9 | CreditsScene::CreditsScene(Game *game) |
7 | 10 | : GameScene(game) { |
8 | 11 | } |
9 | 12 |
|
10 | 13 | void CreditsScene::Initialize() { |
11 | | - // Nothing to initialize |
| 14 | + BuildUI(); |
12 | 15 | } |
13 | 16 |
|
14 | 17 | void CreditsScene::Shutdown() { |
15 | | - // Nothing to clean up |
16 | | - } |
17 | | - |
18 | | - void CreditsScene::Update(const float delta_time) { |
| 18 | + main_panel_.reset(); |
19 | 19 | } |
20 | 20 |
|
21 | | - void CreditsScene::Render() { |
22 | | - ClearBackground(Color{20, 20, 30, 255}); |
| 21 | + void CreditsScene::BuildUI() { |
| 22 | + using namespace engine::ui::components; |
| 23 | + using namespace engine::ui::elements; |
23 | 24 |
|
24 | 25 | std::uint32_t screen_width; |
25 | 26 | std::uint32_t screen_height; |
26 | 27 | engine::rendering::GetRenderer().GetFramebufferSize(screen_width, screen_height); |
| 28 | + last_screen_width_ = screen_width; |
| 29 | + last_screen_height_ = screen_height; |
| 30 | + |
| 31 | + constexpr int PANEL_WIDTH = 600; |
| 32 | + constexpr int PANEL_HEIGHT = 400; |
| 33 | + const float panel_x = static_cast<float>((screen_width - PANEL_WIDTH) / 2); |
| 34 | + const float panel_y = static_cast<float>((screen_height - PANEL_HEIGHT) / 2); |
| 35 | + |
| 36 | + // Create main panel |
| 37 | + main_panel_ = std::make_unique<Panel>(); |
| 38 | + main_panel_->SetRelativePosition(panel_x, panel_y); |
| 39 | + main_panel_->SetSize(static_cast<float>(PANEL_WIDTH), static_cast<float>(PANEL_HEIGHT)); |
| 40 | + main_panel_->SetBackgroundColor(ui::UITheme::ToEngineColor(ColorAlpha(ui::UITheme::BACKGROUND_PANEL, 0.95f))); |
| 41 | + main_panel_->SetBorderColor(ui::UITheme::ToEngineColor(ui::UITheme::PRIMARY)); |
| 42 | + main_panel_->SetPadding(ui::UITheme::PADDING_LARGE); |
| 43 | + |
| 44 | + // Create content container with vertical layout |
| 45 | + auto content = engine::ui::ContainerBuilder() |
| 46 | + .Size(PANEL_WIDTH - ui::UITheme::PADDING_LARGE * 2, PANEL_HEIGHT - ui::UITheme::PADDING_LARGE * 2) |
| 47 | + .Opacity(0) |
| 48 | + .Layout(std::make_unique<VerticalLayout>(ui::UITheme::MARGIN_MEDIUM, Alignment::Center)) |
| 49 | + .Build(); |
| 50 | + |
| 51 | + // Title |
| 52 | + auto title = std::make_unique<Text>( |
| 53 | + 0.0f, 0.0f, |
| 54 | + "CREDITS", |
| 55 | + ui::UITheme::FONT_SIZE_TITLE, |
| 56 | + ui::UITheme::ToEngineColor(GOLD) |
| 57 | + ); |
| 58 | + content->AddChild(std::move(title)); |
| 59 | + |
| 60 | + // Version |
| 61 | + auto version = std::make_unique<Text>( |
| 62 | + 0.0f, 0.0f, |
| 63 | + "TowerForge v0.1.0", |
| 64 | + ui::UITheme::FONT_SIZE_LARGE, |
| 65 | + ui::UITheme::ToEngineColor(WHITE) |
| 66 | + ); |
| 67 | + content->AddChild(std::move(version)); |
| 68 | + |
| 69 | + // Description |
| 70 | + auto description = std::make_unique<Text>( |
| 71 | + 0.0f, 0.0f, |
| 72 | + "A modern SimTower-inspired skyscraper simulation", |
| 73 | + ui::UITheme::FONT_SIZE_NORMAL, |
| 74 | + ui::UITheme::ToEngineColor(LIGHTGRAY) |
| 75 | + ); |
| 76 | + content->AddChild(std::move(description)); |
| 77 | + |
| 78 | + // Divider |
| 79 | + auto divider = std::make_unique<Divider>(); |
| 80 | + divider->SetColor(ui::UITheme::ToEngineColor(ui::UITheme::PRIMARY)); |
| 81 | + divider->SetSize(static_cast<float>(PANEL_WIDTH - ui::UITheme::PADDING_LARGE * 4), 2.0f); |
| 82 | + content->AddChild(std::move(divider)); |
| 83 | + |
| 84 | + // Built with header |
| 85 | + auto built_with = std::make_unique<Text>( |
| 86 | + 0.0f, 0.0f, |
| 87 | + "Built with:", |
| 88 | + ui::UITheme::FONT_SIZE_NORMAL, |
| 89 | + ui::UITheme::ToEngineColor(LIGHTGRAY) |
| 90 | + ); |
| 91 | + content->AddChild(std::move(built_with)); |
| 92 | + |
| 93 | + // Technologies |
| 94 | + const char *technologies[] = {"C++20", "Raylib (rendering)", "Flecs (ECS framework)"}; |
| 95 | + for (const auto *tech: technologies) { |
| 96 | + auto tech_text = std::make_unique<Text>( |
| 97 | + 0.0f, 0.0f, |
| 98 | + std::string("- ") + tech, |
| 99 | + ui::UITheme::FONT_SIZE_NORMAL, |
| 100 | + ui::UITheme::ToEngineColor(WHITE) |
| 101 | + ); |
| 102 | + content->AddChild(std::move(tech_text)); |
| 103 | + } |
| 104 | + |
| 105 | + // Spacer |
| 106 | + auto spacer = std::make_unique<Panel>(); |
| 107 | + spacer->SetSize(1.0f, static_cast<float>(ui::UITheme::MARGIN_LARGE)); |
| 108 | + spacer->SetBackgroundColor({0, 0, 0, 0}); |
| 109 | + content->AddChild(std::move(spacer)); |
27 | 110 |
|
28 | | - int y = 100; |
| 111 | + // Return instruction |
| 112 | + auto return_text = std::make_unique<Text>( |
| 113 | + 0.0f, 0.0f, |
| 114 | + "Press ESC or ENTER to return to menu", |
| 115 | + ui::UITheme::FONT_SIZE_SMALL, |
| 116 | + ui::UITheme::ToEngineColor(GRAY) |
| 117 | + ); |
| 118 | + content->AddChild(std::move(return_text)); |
29 | 119 |
|
30 | | - DrawText("CREDITS", (screen_width - MeasureText("CREDITS", 40)) / 2, y, 40, GOLD); |
31 | | - y += 80; |
| 120 | + main_panel_->AddChild(std::move(content)); |
32 | 121 |
|
33 | | - DrawText("TowerForge v0.1.0", (screen_width - MeasureText("TowerForge v0.1.0", 24)) / 2, y, 24, WHITE); |
34 | | - y += 50; |
| 122 | + main_panel_->InvalidateComponents(); |
| 123 | + main_panel_->UpdateComponentsRecursive(); |
| 124 | + } |
35 | 125 |
|
36 | | - DrawText("A modern SimTower-inspired skyscraper simulation", |
37 | | - (screen_width - MeasureText("A modern SimTower-inspired skyscraper simulation", 18)) / 2, |
38 | | - y, 18, LIGHTGRAY); |
39 | | - y += 60; |
| 126 | + void CreditsScene::UpdateLayout() { |
| 127 | + std::uint32_t screen_width; |
| 128 | + std::uint32_t screen_height; |
| 129 | + engine::rendering::GetRenderer().GetFramebufferSize(screen_width, screen_height); |
40 | 130 |
|
41 | | - DrawText("Built with:", (screen_width - MeasureText("Built with:", 20)) / 2, y, 20, LIGHTGRAY); |
42 | | - y += 40; |
43 | | - DrawText("- C++20", (screen_width - MeasureText("- C++20", 18)) / 2, y, 18, WHITE); |
44 | | - y += 30; |
45 | | - DrawText("- Raylib (rendering)", (screen_width - MeasureText("- Raylib (rendering)", 18)) / 2, y, 18, WHITE); |
46 | | - y += 30; |
47 | | - DrawText("- Flecs (ECS framework)", (screen_width - MeasureText("- Flecs (ECS framework)", 18)) / 2, y, 18, |
48 | | - WHITE); |
49 | | - y += 60; |
| 131 | + if (screen_width != last_screen_width_ || screen_height != last_screen_height_) { |
| 132 | + BuildUI(); |
| 133 | + } |
| 134 | + } |
50 | 135 |
|
51 | | - DrawText("Press ESC or ENTER to return to menu", |
52 | | - (screen_width - MeasureText("Press ESC or ENTER to return to menu", 16)) / 2, |
53 | | - y, 16, GRAY); |
| 136 | + void CreditsScene::Update(const float delta_time) { |
| 137 | + UpdateLayout(); |
| 138 | + } |
| 139 | + |
| 140 | + void CreditsScene::Render() { |
| 141 | + ClearBackground(Color{20, 20, 30, 255}); |
| 142 | + |
| 143 | + engine::ui::BatchRenderer::BeginFrame(); |
| 144 | + if (main_panel_) { |
| 145 | + main_panel_->Render(); |
| 146 | + } |
| 147 | + engine::ui::BatchRenderer::EndFrame(); |
54 | 148 | } |
55 | 149 |
|
56 | 150 | void CreditsScene::HandleMouseEvent(const engine::ui::MouseEvent &event) { |
|
0 commit comments