From f25a7960734515e7c46f97655b22cb22357f8eaf Mon Sep 17 00:00:00 2001 From: HumanoidSandvichDispenser Date: Mon, 16 Mar 2026 01:56:15 -0700 Subject: [PATCH] Add UI --- as6/CMakeLists.txt | 6 +-- as6/Components.hpp | 3 +- as6/EnergyBarRaygui.hpp | 46 +++++++++++++++++++ as6/Entities.cpp | 29 +++++------- as6/Entities.hpp | 2 +- as6/GameContext.hpp | 4 +- as6/components/CollectibleComponent.cpp | 17 +++---- as6/components/GravityReceiverComponent.cpp | 18 ++++---- as6/components/HudComponent.cpp | 5 -- as6/components/HudComponent.hpp | 12 ----- as6/components/MeterComponent.cpp | 21 --------- as6/components/PhysicsComponent.cpp | 8 ++-- as6/components/StatsComponent.cpp | 23 ++++++++++ ...{MeterComponent.hpp => StatsComponent.hpp} | 7 ++- as6/main.cpp | 1 + as6/raygui.cpp | 2 + as6/scene/DeathScene.cpp | 5 +- as6/scene/GameplayScene.cpp | 39 +++------------- as6/scene/GameplayScene.hpp | 1 - as6/scene/Scene.hpp | 17 ++++++- as6/scene/StartMenuScene.cpp | 8 ++-- 21 files changed, 142 insertions(+), 132 deletions(-) create mode 100644 as6/EnergyBarRaygui.hpp delete mode 100644 as6/components/HudComponent.cpp delete mode 100644 as6/components/HudComponent.hpp delete mode 100644 as6/components/MeterComponent.cpp create mode 100644 as6/components/StatsComponent.cpp rename as6/components/{MeterComponent.hpp => StatsComponent.hpp} (65%) create mode 100644 as6/raygui.cpp diff --git a/as6/CMakeLists.txt b/as6/CMakeLists.txt index 9b0e997..46ab01e 100644 --- a/as6/CMakeLists.txt +++ b/as6/CMakeLists.txt @@ -14,6 +14,7 @@ include(../assets/includeable.cmake) add_executable(as6-gravity-surfing main.cpp + raygui.cpp Draw.cpp Entities.cpp Systems.cpp @@ -21,7 +22,6 @@ add_executable(as6-gravity-surfing components/PhysicsComponent.cpp components/GravityWellComponent.cpp components/ScrollComponent.cpp - components/MeterComponent.cpp components/NullZoneComponent.cpp components/ColliderComponent.cpp components/ScrollableComponent.cpp @@ -33,13 +33,13 @@ add_executable(as6-gravity-surfing components/HazardComponent.cpp components/GravityReceiverComponent.cpp components/ProbeStateComponent.cpp - components/HudComponent.cpp + components/StatsComponent.cpp components/RenderComponent.cpp scene/StartMenuScene.cpp scene/GameplayScene.cpp scene/DeathScene.cpp ) -target_link_libraries(as6-gravity-surfing PUBLIC raylib raylib_cpp buffered-raylib) +target_link_libraries(as6-gravity-surfing PUBLIC raylib raylib_cpp buffered-raylib raygui) target_include_directories(as6-gravity-surfing PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/as6/Components.hpp b/as6/Components.hpp index 1232e6a..a991d16 100644 --- a/as6/Components.hpp +++ b/as6/Components.hpp @@ -5,9 +5,7 @@ #include "components/GravityReceiverComponent.hpp" #include "components/GravityWellComponent.hpp" #include "components/HazardComponent.hpp" -#include "components/HudComponent.hpp" #include "components/LifetimeComponent.hpp" -#include "components/MeterComponent.hpp" #include "components/NullZoneComponent.hpp" #include "components/PhysicsComponent.hpp" #include "components/ProbeStateComponent.hpp" @@ -16,5 +14,6 @@ #include "components/ScrollComponent.hpp" #include "components/ScrollableComponent.hpp" #include "components/SpawnComponent.hpp" +#include "components/StatsComponent.hpp" #include "components/TrailComponent.hpp" #include "components/TransformComponent.hpp" diff --git a/as6/EnergyBarRaygui.hpp b/as6/EnergyBarRaygui.hpp new file mode 100644 index 0000000..c269e17 --- /dev/null +++ b/as6/EnergyBarRaygui.hpp @@ -0,0 +1,46 @@ +/******************************************************************************************* + * + * LayoutName v1.0.0 - Tool Description + * + * LICENSE: Propietary License + * + * Copyright (c) 2022 raylib technologies. All Rights Reserved. + * + * Unauthorized copying of this file, via any medium is strictly prohibited + * This project is proprietary and confidential unless the owner allows + * usage in any other form by expresely written permission. + * + **********************************************************************************************/ + +#pragma once + +#include "raygui.h" +#include "raylib.h" + +inline constexpr int WINDOW_WIDTH = 700; +inline constexpr int WINDOW_HEIGHT = 460; + +//---------------------------------------------------------------------------------- +// Controls Functions Declaration +//---------------------------------------------------------------------------------- + +inline void DrawHud(float value, int stars) { + GuiProgressBar((Rectangle){72, 440, 120, 16}, "ENERGY", nullptr, value, 0, 1); + GuiLabel((Rectangle){24, 8, 120, 24}, TextFormat("STARS: x%d", stars)); +} + +inline void DrawMainMenu() { + GuiLabel((Rectangle){WINDOW_WIDTH / 2 - 100, WINDOW_HEIGHT / 2 - 60, 200, 40}, + "GRAVITY SURFING"); + + GuiLabel((Rectangle){WINDOW_WIDTH / 2 - 200, WINDOW_HEIGHT / 2, 400, 60}, + "LEFT CLICK to turn on gravity well and attract probe\n" + "Avoid hazards and collect stars to keep your meter from draining\n" + "If your meter runs out, gravity well turns off and you lose control\n" + "until you collect another star\n" + "Press SPACE or LEFT CLICK to start"); +} + +//------------------------------------------------------------------------------------ +// Controls Functions Definitions (local) +//------------------------------------------------------------------------------------ diff --git a/as6/Entities.cpp b/as6/Entities.cpp index be4bdae..6ea1bc5 100644 --- a/as6/Entities.cpp +++ b/as6/Entities.cpp @@ -2,7 +2,8 @@ #include "Components.hpp" -#include "raylib.h" +#include "EnergyBarRaygui.hpp" +#include std::shared_ptr CreateProbe() { auto e = std::make_shared(); @@ -13,7 +14,7 @@ std::shared_ptr CreateProbe() { e->AddComponent(); auto &physics = e->AddComponent(); - physics.vx = 108.0f; + physics.vx = 16.0f; physics.vy = 0.0f; physics.speedCap = 8192.0f; @@ -41,8 +42,7 @@ std::shared_ptr CreateProbe() { DrawCircleV({transform->get().x, transform->get().y}, 7.0f, PROBE_COLOR); - DrawCircleV({transform->get().x - 1, transform->get().y - 1}, 3.0f, - PROBE_HIGHLIGHT); + DrawCircleV({transform->get().x - 1, transform->get().y - 1}, 3.0f, PROBE_HIGHLIGHT); }; return e; } @@ -164,8 +164,7 @@ std::shared_ptr CreateNullZone(float x, float width) { int x = (int)(transform->get().x); - DrawRectangle(x, 0, (int)(zone->get().width), - GetScreenHeight(), Color{96, 64, 146, 80}); + DrawRectangle(x, 0, (int)(zone->get().width), GetScreenHeight(), Color{96, 64, 146, 80}); DrawText("Null Zone", x + 8, 12, 16, Color{96, 64, 146, 200}); }; @@ -179,24 +178,18 @@ std::shared_ptr CreateWorld() { return e; } -std::shared_ptr CreateHUD() { +std::shared_ptr CreateStats() { auto e = std::make_shared(); - e->AddComponent(); - e->AddComponent(); + e->AddComponent(); auto &render = e->AddComponent(); render.draw = [e]() { - auto meter = e->GetComponent(); - if (!meter) { + auto stats = e->GetComponent(); + if (!stats) { return; } - const float t = std::clamp(meter->get().value / 100.0f, 0.0f, 1.0f); - const int x = 14; - const int y = 86; - const int w = 240; - const int h = 14; - DrawRectangleLines(x, y, w, h, Color{125, 140, 165, 255}); - DrawRectangle(x + 1, y + 1, static_cast((w - 2) * t), h - 2, Color{60, 199, 178, 255}); + const float ratio = std::clamp(stats->get().value / stats->get().maxValue, 0.0f, 1.0f); + DrawHud(ratio, stats->get().GetStarCount()); }; return e; } diff --git a/as6/Entities.hpp b/as6/Entities.hpp index ddb3f2b..22d411f 100644 --- a/as6/Entities.hpp +++ b/as6/Entities.hpp @@ -11,4 +11,4 @@ std::shared_ptr CreateAsteroid(float x, float y); std::shared_ptr CreateDebris(float x, float y, float vx, float vy, float ttl = 1.25f); std::shared_ptr CreateNullZone(float x, float width); std::shared_ptr CreateWorld(); -std::shared_ptr CreateHUD(); +std::shared_ptr CreateStats(); diff --git a/as6/GameContext.hpp b/as6/GameContext.hpp index 70f6ab8..f6e202d 100644 --- a/as6/GameContext.hpp +++ b/as6/GameContext.hpp @@ -21,8 +21,8 @@ struct GameContext { Entity *wellEntity = nullptr; /** @brief Player probe entity. */ Entity *probeEntity = nullptr; - /** @brief HUD entity. */ - Entity *hudEntity = nullptr; + /** @brief Stats entity that owns meter + star records. */ + Entity *statsEntity = nullptr; /** @brief Shared horizontal world scroll value. */ float scrollX = 0.0f; diff --git a/as6/components/CollectibleComponent.cpp b/as6/components/CollectibleComponent.cpp index 5a9f4a8..f350970 100644 --- a/as6/components/CollectibleComponent.cpp +++ b/as6/components/CollectibleComponent.cpp @@ -2,7 +2,7 @@ #include "Entity.hpp" #include "components/ColliderComponent.hpp" -#include "components/MeterComponent.hpp" +#include "components/StatsComponent.hpp" void CollectibleComponent::Setup() { auto selfCollider = entity->GetComponent(); @@ -21,16 +21,13 @@ void CollectibleComponent::Setup() { context->EmitCollectiblePicked(*entity); entity->QueueFree(); - if (!context->hudEntity) { - return; + if (context->statsEntity) { + auto stats = context->statsEntity->GetComponent(); + if (stats) { + stats->get().AddValue(stats->get().gainPerStar); + stats->get().AddStar(); + } } - - auto meter = context->hudEntity->GetComponent(); - if (!meter) { - return; - } - - meter->get().AddValue(meter->get().gainPerStar); }); } diff --git a/as6/components/GravityReceiverComponent.cpp b/as6/components/GravityReceiverComponent.cpp index b7b751c..9be390a 100644 --- a/as6/components/GravityReceiverComponent.cpp +++ b/as6/components/GravityReceiverComponent.cpp @@ -2,9 +2,9 @@ #include "Entity.hpp" #include "components/GravityWellComponent.hpp" -#include "components/MeterComponent.hpp" #include "components/NullZoneComponent.hpp" #include "components/PhysicsComponent.hpp" +#include "components/StatsComponent.hpp" #include "components/TransformComponent.hpp" #include @@ -32,18 +32,18 @@ void GravityReceiverComponent::Update(float dt) { return; } - MeterComponent *meterPtr = nullptr; - if (context->hudEntity) { - auto meter = context->hudEntity->GetComponent(); - if (meter) { - meterPtr = &meter->get(); + StatsComponent *statsPtr = nullptr; + if (context->statsEntity) { + auto stats = context->statsEntity->GetComponent(); + if (stats) { + statsPtr = &stats->get(); } } if (!wellGravity->get().active) { return; } - if (meterPtr && meterPtr->value <= 0.0f) { + if (statsPtr && statsPtr->value <= 0.0f) { return; } @@ -87,8 +87,8 @@ void GravityReceiverComponent::Update(float dt) { physics->get().vx += nx * force * dt; physics->get().vy += ny * force * dt; - if (meterPtr) { - meterPtr->Drain(meterPtr->drainRate * dt); + if (statsPtr) { + statsPtr->Drain(statsPtr->drainRate * dt); } } diff --git a/as6/components/HudComponent.cpp b/as6/components/HudComponent.cpp deleted file mode 100644 index 1fd2c93..0000000 --- a/as6/components/HudComponent.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "components/HudComponent.hpp" - -void HudComponent::Setup() {} -void HudComponent::Update(float) {} -void HudComponent::Cleanup() {} diff --git a/as6/components/HudComponent.hpp b/as6/components/HudComponent.hpp deleted file mode 100644 index 75ff8b1..0000000 --- a/as6/components/HudComponent.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "Component.hpp" - -/** - * Marker component for HUD entities. - */ -struct HudComponent : public Component { - void Setup() override; - void Update(float dt) override; - void Cleanup() override; -}; diff --git a/as6/components/MeterComponent.cpp b/as6/components/MeterComponent.cpp deleted file mode 100644 index 73259e1..0000000 --- a/as6/components/MeterComponent.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "components/MeterComponent.hpp" - -#include - -void MeterComponent::Setup() {} - -void MeterComponent::SetValue(float newValue) { - const float oldValue = value; - value = newValue; - if (context && oldValue != value) { - context->EmitMeterChanged(oldValue, value); - } -} - -void MeterComponent::AddValue(float delta) { SetValue(std::clamp(value + delta, 0.0f, maxValue)); } - -void MeterComponent::Drain(float amount) { AddValue(-amount); } - -void MeterComponent::Update(float) {} - -void MeterComponent::Cleanup() {} diff --git a/as6/components/PhysicsComponent.cpp b/as6/components/PhysicsComponent.cpp index 9c0f7ec..290b25c 100644 --- a/as6/components/PhysicsComponent.cpp +++ b/as6/components/PhysicsComponent.cpp @@ -2,8 +2,8 @@ #include "Entity.hpp" #include "components/GravityWellComponent.hpp" -#include "components/MeterComponent.hpp" #include "components/NullZoneComponent.hpp" +#include "components/StatsComponent.hpp" #include "components/TransformComponent.hpp" #include @@ -87,9 +87,9 @@ bool PhysicsComponent::ComputeWellDeltaVelocity(double px, double py, double dt, } // Probe cannot receive well acceleration when meter is depleted. - if (context && entity == context->probeEntity && context->hudEntity) { - auto meter = context->hudEntity->GetComponent(); - if (meter && meter->get().value <= 0.0f) { + if (context && entity == context->probeEntity && context->statsEntity) { + auto stats = context->statsEntity->GetComponent(); + if (stats && stats->get().value <= 0.0f) { return false; } } diff --git a/as6/components/StatsComponent.cpp b/as6/components/StatsComponent.cpp new file mode 100644 index 0000000..4f51b73 --- /dev/null +++ b/as6/components/StatsComponent.cpp @@ -0,0 +1,23 @@ +#include "components/StatsComponent.hpp" + +void StatsComponent::Setup() {} + +void StatsComponent::SetValue(float newValue) { + const float oldValue = value; + value = newValue; + if (context && oldValue != value) { + context->EmitMeterChanged(oldValue, value); + } +} + +void StatsComponent::AddValue(float delta) { SetValue(std::clamp(value + delta, 0.0f, maxValue)); } + +void StatsComponent::Drain(float amount) { AddValue(-amount); } + +void StatsComponent::AddStar() { ++stars; } + +int StatsComponent::GetStarCount() const { return stars; } + +void StatsComponent::Update(float) {} + +void StatsComponent::Cleanup() {} diff --git a/as6/components/MeterComponent.hpp b/as6/components/StatsComponent.hpp similarity index 65% rename from as6/components/MeterComponent.hpp rename to as6/components/StatsComponent.hpp index f0b46e5..2ef38d6 100644 --- a/as6/components/MeterComponent.hpp +++ b/as6/components/StatsComponent.hpp @@ -5,18 +5,21 @@ #include /** - * Stores and mutates the player's gravity meter with change events. + * Stores persistent gameplay stats such as the gravity meter and collected stars. */ -struct MeterComponent : public Component { +struct StatsComponent : public Component { float value = 60.0f; float maxValue = 100.0f; float drainRate = 14.0f; float gainPerStar = 28.0f; + int stars = 0; void Setup() override; void SetValue(float newValue); void AddValue(float delta); void Drain(float amount); + void AddStar(); + int GetStarCount() const; void Update(float dt) override; void Cleanup() override; }; diff --git a/as6/main.cpp b/as6/main.cpp index a4ac757..a8ea6b4 100644 --- a/as6/main.cpp +++ b/as6/main.cpp @@ -1,5 +1,6 @@ #include "Components.hpp" #include "Draw.hpp" +#include "EnergyBarRaygui.hpp" #include "Entities.hpp" #include "Entity.hpp" #include "GameContext.hpp" diff --git a/as6/raygui.cpp b/as6/raygui.cpp new file mode 100644 index 0000000..1878467 --- /dev/null +++ b/as6/raygui.cpp @@ -0,0 +1,2 @@ +#define RAYGUI_IMPLEMENTATION +#include "raygui.h" diff --git a/as6/scene/DeathScene.cpp b/as6/scene/DeathScene.cpp index c5ec1cc..25d0a40 100644 --- a/as6/scene/DeathScene.cpp +++ b/as6/scene/DeathScene.cpp @@ -16,8 +16,5 @@ void DeathScene::Update(float) { } void DeathScene::Draw() { - DrawSceneOutline(); - DrawText("PROBE LOST", 24, 28, 36, Color{255, 208, 208, 255}); - DrawText("Press Enter or click to restart", 24, 84, 22, Color{255, 170, 170, 255}); - DrawText("Press Esc for menu", 24, 116, 20, Color{200, 188, 188, 255}); + Scene::Draw(); } diff --git a/as6/scene/GameplayScene.cpp b/as6/scene/GameplayScene.cpp index dd2eb13..e1d0c83 100644 --- a/as6/scene/GameplayScene.cpp +++ b/as6/scene/GameplayScene.cpp @@ -1,5 +1,6 @@ #include "scene/GameplayScene.hpp" +#include "EnergyBarRaygui.hpp" #include "scene/DeathScene.hpp" #include "scene/SceneManager.hpp" @@ -36,12 +37,12 @@ void GameplayScene::Enter() { entities.emplace_back(CreateStar(900.0f, 230.0f)); entities.emplace_back(CreateNullZone(1280.0f, 120.0f)); - context.hudEntity = entities.emplace_back(CreateHUD()).get(); + context.statsEntity = entities.emplace_back(CreateStats()).get(); - if (context.hudEntity) { - auto meter = context.hudEntity->GetComponent(); - if (meter) { - meterValue = meter->get().value; + if (context.statsEntity) { + auto stats = context.statsEntity->GetComponent(); + if (stats) { + meterValue = stats->get().value; } } @@ -64,9 +65,6 @@ void GameplayScene::Update(float dt) { } void GameplayScene::Draw() { - DrawSceneOutline(); - DrawText("Gravity Surfing", 14, 12, 20, Color{230, 238, 255, 255}); - std::optional> worldScroll; if (context.worldEntity) { worldScroll = context.worldEntity->GetComponent(); @@ -77,28 +75,5 @@ void GameplayScene::Draw() { probeTransform = context.probeEntity->GetComponent(); } - if (worldScroll) { - DrawText(TextFormat("scrollX: %.2f", worldScroll->get().scrollX), 14, 40, 16, - Color{125, 225, 205, 255}); - } - - if (probeTransform) { - const auto &probe = probeTransform->get(); - DrawText(TextFormat("probe: (%.1f, %.1f)", probe.x, probe.y), 14, 60, 16, - Color{235, 215, 125, 255}); - } - - DrawText(TextFormat("meter: %.1f", meterValue), 14, 80, 16, Color{120, 210, 190, 255}); - DrawText(TextFormat("stars: %i", collectedCount), 14, 100, 16, Color{255, 223, 86, 255}); - - for (auto &entity : entities) { - if (!entity || entity->queuedForFree) { - continue; - } - - auto render = entity->GetComponent(); - if (render) { - render->get().Draw(); - } - } + Scene::Draw(); } diff --git a/as6/scene/GameplayScene.hpp b/as6/scene/GameplayScene.hpp index 65f55e8..92ff2bc 100644 --- a/as6/scene/GameplayScene.hpp +++ b/as6/scene/GameplayScene.hpp @@ -25,7 +25,6 @@ class GameplayScene : public Scene { void Draw() override; private: - std::vector> entities; GameContext context; bool wantsDeathScene = false; int collectedCount = 0; diff --git a/as6/scene/Scene.hpp b/as6/scene/Scene.hpp index 4c2f0f1..fadd543 100644 --- a/as6/scene/Scene.hpp +++ b/as6/scene/Scene.hpp @@ -1,5 +1,8 @@ #pragma once +#include "Components.hpp" +#include "Entity.hpp" + class SceneManager; /** @@ -7,13 +10,25 @@ class SceneManager; */ class Scene { public: + std::vector> entities; explicit Scene(SceneManager &owner) : manager(owner) {} virtual ~Scene() = default; virtual void Enter() {} virtual void Exit() {} virtual void Update(float dt) = 0; - virtual void Draw() = 0; + virtual void Draw() { + for (auto &entity : entities) { + if (!entity || entity->queuedForFree) { + continue; + } + + auto render = entity->GetComponent(); + if (render) { + render->get().Draw(); + } + } + } protected: SceneManager &manager; diff --git a/as6/scene/StartMenuScene.cpp b/as6/scene/StartMenuScene.cpp index 9405aba..ae1de53 100644 --- a/as6/scene/StartMenuScene.cpp +++ b/as6/scene/StartMenuScene.cpp @@ -1,5 +1,6 @@ #include "scene/StartMenuScene.hpp" +#include "EnergyBarRaygui.hpp" #include "scene/GameplayScene.hpp" #include "scene/SceneManager.hpp" @@ -10,9 +11,6 @@ void StartMenuScene::Update(float) { } void StartMenuScene::Draw() { - DrawSceneOutline(); - DrawText("Gravity Surfing", 24, 28, 36, Color{230, 238, 255, 255}); - DrawText("Click or press Enter to start", 24, 78, 22, Color{140, 198, 220, 255}); - DrawText("Left mouse controls gravity well", 24, 130, 18, Color{170, 185, 205, 255}); - DrawText("Collect stars and dodge hazards", 24, 156, 18, Color{170, 185, 205, 255}); + DrawMainMenu(); + Scene::Draw(); }