master
John Montagu, the 4th Earl of Sandvich 2026-03-16 01:56:15 -07:00
parent 50066db8ef
commit f25a796073
Signed by: sandvich
GPG Key ID: 9A39BE37E602B22D
21 changed files with 142 additions and 132 deletions

View File

@ -14,6 +14,7 @@ include(../assets/includeable.cmake)
add_executable(as6-gravity-surfing add_executable(as6-gravity-surfing
main.cpp main.cpp
raygui.cpp
Draw.cpp Draw.cpp
Entities.cpp Entities.cpp
Systems.cpp Systems.cpp
@ -21,7 +22,6 @@ add_executable(as6-gravity-surfing
components/PhysicsComponent.cpp components/PhysicsComponent.cpp
components/GravityWellComponent.cpp components/GravityWellComponent.cpp
components/ScrollComponent.cpp components/ScrollComponent.cpp
components/MeterComponent.cpp
components/NullZoneComponent.cpp components/NullZoneComponent.cpp
components/ColliderComponent.cpp components/ColliderComponent.cpp
components/ScrollableComponent.cpp components/ScrollableComponent.cpp
@ -33,13 +33,13 @@ add_executable(as6-gravity-surfing
components/HazardComponent.cpp components/HazardComponent.cpp
components/GravityReceiverComponent.cpp components/GravityReceiverComponent.cpp
components/ProbeStateComponent.cpp components/ProbeStateComponent.cpp
components/HudComponent.cpp components/StatsComponent.cpp
components/RenderComponent.cpp components/RenderComponent.cpp
scene/StartMenuScene.cpp scene/StartMenuScene.cpp
scene/GameplayScene.cpp scene/GameplayScene.cpp
scene/DeathScene.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 target_include_directories(as6-gravity-surfing PRIVATE
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}

View File

@ -5,9 +5,7 @@
#include "components/GravityReceiverComponent.hpp" #include "components/GravityReceiverComponent.hpp"
#include "components/GravityWellComponent.hpp" #include "components/GravityWellComponent.hpp"
#include "components/HazardComponent.hpp" #include "components/HazardComponent.hpp"
#include "components/HudComponent.hpp"
#include "components/LifetimeComponent.hpp" #include "components/LifetimeComponent.hpp"
#include "components/MeterComponent.hpp"
#include "components/NullZoneComponent.hpp" #include "components/NullZoneComponent.hpp"
#include "components/PhysicsComponent.hpp" #include "components/PhysicsComponent.hpp"
#include "components/ProbeStateComponent.hpp" #include "components/ProbeStateComponent.hpp"
@ -16,5 +14,6 @@
#include "components/ScrollComponent.hpp" #include "components/ScrollComponent.hpp"
#include "components/ScrollableComponent.hpp" #include "components/ScrollableComponent.hpp"
#include "components/SpawnComponent.hpp" #include "components/SpawnComponent.hpp"
#include "components/StatsComponent.hpp"
#include "components/TrailComponent.hpp" #include "components/TrailComponent.hpp"
#include "components/TransformComponent.hpp" #include "components/TransformComponent.hpp"

View File

@ -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)
//------------------------------------------------------------------------------------

View File

@ -2,7 +2,8 @@
#include "Components.hpp" #include "Components.hpp"
#include "raylib.h" #include "EnergyBarRaygui.hpp"
#include <algorithm>
std::shared_ptr<Entity> CreateProbe() { std::shared_ptr<Entity> CreateProbe() {
auto e = std::make_shared<Entity>(); auto e = std::make_shared<Entity>();
@ -13,7 +14,7 @@ std::shared_ptr<Entity> CreateProbe() {
e->AddComponent<GravityReceiverComponent>(); e->AddComponent<GravityReceiverComponent>();
auto &physics = e->AddComponent<PhysicsComponent>(); auto &physics = e->AddComponent<PhysicsComponent>();
physics.vx = 108.0f; physics.vx = 16.0f;
physics.vy = 0.0f; physics.vy = 0.0f;
physics.speedCap = 8192.0f; physics.speedCap = 8192.0f;
@ -41,8 +42,7 @@ std::shared_ptr<Entity> CreateProbe() {
DrawCircleV({transform->get().x, transform->get().y}, 7.0f, PROBE_COLOR); DrawCircleV({transform->get().x, transform->get().y}, 7.0f, PROBE_COLOR);
DrawCircleV({transform->get().x - 1, transform->get().y - 1}, 3.0f, DrawCircleV({transform->get().x - 1, transform->get().y - 1}, 3.0f, PROBE_HIGHLIGHT);
PROBE_HIGHLIGHT);
}; };
return e; return e;
} }
@ -164,8 +164,7 @@ std::shared_ptr<Entity> CreateNullZone(float x, float width) {
int x = (int)(transform->get().x); int x = (int)(transform->get().x);
DrawRectangle(x, 0, (int)(zone->get().width), DrawRectangle(x, 0, (int)(zone->get().width), GetScreenHeight(), Color{96, 64, 146, 80});
GetScreenHeight(), Color{96, 64, 146, 80});
DrawText("Null Zone", x + 8, 12, 16, Color{96, 64, 146, 200}); DrawText("Null Zone", x + 8, 12, 16, Color{96, 64, 146, 200});
}; };
@ -179,24 +178,18 @@ std::shared_ptr<Entity> CreateWorld() {
return e; return e;
} }
std::shared_ptr<Entity> CreateHUD() { std::shared_ptr<Entity> CreateStats() {
auto e = std::make_shared<Entity>(); auto e = std::make_shared<Entity>();
e->AddComponent<MeterComponent>(); e->AddComponent<StatsComponent>();
e->AddComponent<HudComponent>();
auto &render = e->AddComponent<RenderComponent>(); auto &render = e->AddComponent<RenderComponent>();
render.draw = [e]() { render.draw = [e]() {
auto meter = e->GetComponent<MeterComponent>(); auto stats = e->GetComponent<StatsComponent>();
if (!meter) { if (!stats) {
return; return;
} }
const float t = std::clamp(meter->get().value / 100.0f, 0.0f, 1.0f); const float ratio = std::clamp(stats->get().value / stats->get().maxValue, 0.0f, 1.0f);
const int x = 14; DrawHud(ratio, stats->get().GetStarCount());
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<int>((w - 2) * t), h - 2, Color{60, 199, 178, 255});
}; };
return e; return e;
} }

View File

@ -11,4 +11,4 @@ std::shared_ptr<Entity> CreateAsteroid(float x, float y);
std::shared_ptr<Entity> CreateDebris(float x, float y, float vx, float vy, float ttl = 1.25f); std::shared_ptr<Entity> CreateDebris(float x, float y, float vx, float vy, float ttl = 1.25f);
std::shared_ptr<Entity> CreateNullZone(float x, float width); std::shared_ptr<Entity> CreateNullZone(float x, float width);
std::shared_ptr<Entity> CreateWorld(); std::shared_ptr<Entity> CreateWorld();
std::shared_ptr<Entity> CreateHUD(); std::shared_ptr<Entity> CreateStats();

View File

@ -21,8 +21,8 @@ struct GameContext {
Entity *wellEntity = nullptr; Entity *wellEntity = nullptr;
/** @brief Player probe entity. */ /** @brief Player probe entity. */
Entity *probeEntity = nullptr; Entity *probeEntity = nullptr;
/** @brief HUD entity. */ /** @brief Stats entity that owns meter + star records. */
Entity *hudEntity = nullptr; Entity *statsEntity = nullptr;
/** @brief Shared horizontal world scroll value. */ /** @brief Shared horizontal world scroll value. */
float scrollX = 0.0f; float scrollX = 0.0f;

View File

@ -2,7 +2,7 @@
#include "Entity.hpp" #include "Entity.hpp"
#include "components/ColliderComponent.hpp" #include "components/ColliderComponent.hpp"
#include "components/MeterComponent.hpp" #include "components/StatsComponent.hpp"
void CollectibleComponent::Setup() { void CollectibleComponent::Setup() {
auto selfCollider = entity->GetComponent<ColliderComponent>(); auto selfCollider = entity->GetComponent<ColliderComponent>();
@ -21,16 +21,13 @@ void CollectibleComponent::Setup() {
context->EmitCollectiblePicked(*entity); context->EmitCollectiblePicked(*entity);
entity->QueueFree(); entity->QueueFree();
if (!context->hudEntity) { if (context->statsEntity) {
return; auto stats = context->statsEntity->GetComponent<StatsComponent>();
if (stats) {
stats->get().AddValue(stats->get().gainPerStar);
stats->get().AddStar();
}
} }
auto meter = context->hudEntity->GetComponent<MeterComponent>();
if (!meter) {
return;
}
meter->get().AddValue(meter->get().gainPerStar);
}); });
} }

View File

@ -2,9 +2,9 @@
#include "Entity.hpp" #include "Entity.hpp"
#include "components/GravityWellComponent.hpp" #include "components/GravityWellComponent.hpp"
#include "components/MeterComponent.hpp"
#include "components/NullZoneComponent.hpp" #include "components/NullZoneComponent.hpp"
#include "components/PhysicsComponent.hpp" #include "components/PhysicsComponent.hpp"
#include "components/StatsComponent.hpp"
#include "components/TransformComponent.hpp" #include "components/TransformComponent.hpp"
#include <algorithm> #include <algorithm>
@ -32,18 +32,18 @@ void GravityReceiverComponent::Update(float dt) {
return; return;
} }
MeterComponent *meterPtr = nullptr; StatsComponent *statsPtr = nullptr;
if (context->hudEntity) { if (context->statsEntity) {
auto meter = context->hudEntity->GetComponent<MeterComponent>(); auto stats = context->statsEntity->GetComponent<StatsComponent>();
if (meter) { if (stats) {
meterPtr = &meter->get(); statsPtr = &stats->get();
} }
} }
if (!wellGravity->get().active) { if (!wellGravity->get().active) {
return; return;
} }
if (meterPtr && meterPtr->value <= 0.0f) { if (statsPtr && statsPtr->value <= 0.0f) {
return; return;
} }
@ -87,8 +87,8 @@ void GravityReceiverComponent::Update(float dt) {
physics->get().vx += nx * force * dt; physics->get().vx += nx * force * dt;
physics->get().vy += ny * force * dt; physics->get().vy += ny * force * dt;
if (meterPtr) { if (statsPtr) {
meterPtr->Drain(meterPtr->drainRate * dt); statsPtr->Drain(statsPtr->drainRate * dt);
} }
} }

View File

@ -1,5 +0,0 @@
#include "components/HudComponent.hpp"
void HudComponent::Setup() {}
void HudComponent::Update(float) {}
void HudComponent::Cleanup() {}

View File

@ -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;
};

View File

@ -1,21 +0,0 @@
#include "components/MeterComponent.hpp"
#include <algorithm>
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() {}

View File

@ -2,8 +2,8 @@
#include "Entity.hpp" #include "Entity.hpp"
#include "components/GravityWellComponent.hpp" #include "components/GravityWellComponent.hpp"
#include "components/MeterComponent.hpp"
#include "components/NullZoneComponent.hpp" #include "components/NullZoneComponent.hpp"
#include "components/StatsComponent.hpp"
#include "components/TransformComponent.hpp" #include "components/TransformComponent.hpp"
#include <algorithm> #include <algorithm>
@ -87,9 +87,9 @@ bool PhysicsComponent::ComputeWellDeltaVelocity(double px, double py, double dt,
} }
// Probe cannot receive well acceleration when meter is depleted. // Probe cannot receive well acceleration when meter is depleted.
if (context && entity == context->probeEntity && context->hudEntity) { if (context && entity == context->probeEntity && context->statsEntity) {
auto meter = context->hudEntity->GetComponent<MeterComponent>(); auto stats = context->statsEntity->GetComponent<StatsComponent>();
if (meter && meter->get().value <= 0.0f) { if (stats && stats->get().value <= 0.0f) {
return false; return false;
} }
} }

View File

@ -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() {}

View File

@ -5,18 +5,21 @@
#include <algorithm> #include <algorithm>
/** /**
* 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 value = 60.0f;
float maxValue = 100.0f; float maxValue = 100.0f;
float drainRate = 14.0f; float drainRate = 14.0f;
float gainPerStar = 28.0f; float gainPerStar = 28.0f;
int stars = 0;
void Setup() override; void Setup() override;
void SetValue(float newValue); void SetValue(float newValue);
void AddValue(float delta); void AddValue(float delta);
void Drain(float amount); void Drain(float amount);
void AddStar();
int GetStarCount() const;
void Update(float dt) override; void Update(float dt) override;
void Cleanup() override; void Cleanup() override;
}; };

View File

@ -1,5 +1,6 @@
#include "Components.hpp" #include "Components.hpp"
#include "Draw.hpp" #include "Draw.hpp"
#include "EnergyBarRaygui.hpp"
#include "Entities.hpp" #include "Entities.hpp"
#include "Entity.hpp" #include "Entity.hpp"
#include "GameContext.hpp" #include "GameContext.hpp"

2
as6/raygui.cpp 100644
View File

@ -0,0 +1,2 @@
#define RAYGUI_IMPLEMENTATION
#include "raygui.h"

View File

@ -16,8 +16,5 @@ void DeathScene::Update(float) {
} }
void DeathScene::Draw() { void DeathScene::Draw() {
DrawSceneOutline(); Scene::Draw();
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});
} }

View File

@ -1,5 +1,6 @@
#include "scene/GameplayScene.hpp" #include "scene/GameplayScene.hpp"
#include "EnergyBarRaygui.hpp"
#include "scene/DeathScene.hpp" #include "scene/DeathScene.hpp"
#include "scene/SceneManager.hpp" #include "scene/SceneManager.hpp"
@ -36,12 +37,12 @@ void GameplayScene::Enter() {
entities.emplace_back(CreateStar(900.0f, 230.0f)); entities.emplace_back(CreateStar(900.0f, 230.0f));
entities.emplace_back(CreateNullZone(1280.0f, 120.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) { if (context.statsEntity) {
auto meter = context.hudEntity->GetComponent<MeterComponent>(); auto stats = context.statsEntity->GetComponent<StatsComponent>();
if (meter) { if (stats) {
meterValue = meter->get().value; meterValue = stats->get().value;
} }
} }
@ -64,9 +65,6 @@ void GameplayScene::Update(float dt) {
} }
void GameplayScene::Draw() { void GameplayScene::Draw() {
DrawSceneOutline();
DrawText("Gravity Surfing", 14, 12, 20, Color{230, 238, 255, 255});
std::optional<std::reference_wrapper<ScrollComponent>> worldScroll; std::optional<std::reference_wrapper<ScrollComponent>> worldScroll;
if (context.worldEntity) { if (context.worldEntity) {
worldScroll = context.worldEntity->GetComponent<ScrollComponent>(); worldScroll = context.worldEntity->GetComponent<ScrollComponent>();
@ -77,28 +75,5 @@ void GameplayScene::Draw() {
probeTransform = context.probeEntity->GetComponent<TransformComponent>(); probeTransform = context.probeEntity->GetComponent<TransformComponent>();
} }
if (worldScroll) { Scene::Draw();
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<RenderComponent>();
if (render) {
render->get().Draw();
}
}
} }

View File

@ -25,7 +25,6 @@ class GameplayScene : public Scene {
void Draw() override; void Draw() override;
private: private:
std::vector<std::shared_ptr<Entity>> entities;
GameContext context; GameContext context;
bool wantsDeathScene = false; bool wantsDeathScene = false;
int collectedCount = 0; int collectedCount = 0;

View File

@ -1,5 +1,8 @@
#pragma once #pragma once
#include "Components.hpp"
#include "Entity.hpp"
class SceneManager; class SceneManager;
/** /**
@ -7,13 +10,25 @@ class SceneManager;
*/ */
class Scene { class Scene {
public: public:
std::vector<std::shared_ptr<Entity>> entities;
explicit Scene(SceneManager &owner) : manager(owner) {} explicit Scene(SceneManager &owner) : manager(owner) {}
virtual ~Scene() = default; virtual ~Scene() = default;
virtual void Enter() {} virtual void Enter() {}
virtual void Exit() {} virtual void Exit() {}
virtual void Update(float dt) = 0; 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<RenderComponent>();
if (render) {
render->get().Draw();
}
}
}
protected: protected:
SceneManager &manager; SceneManager &manager;

View File

@ -1,5 +1,6 @@
#include "scene/StartMenuScene.hpp" #include "scene/StartMenuScene.hpp"
#include "EnergyBarRaygui.hpp"
#include "scene/GameplayScene.hpp" #include "scene/GameplayScene.hpp"
#include "scene/SceneManager.hpp" #include "scene/SceneManager.hpp"
@ -10,9 +11,6 @@ void StartMenuScene::Update(float) {
} }
void StartMenuScene::Draw() { void StartMenuScene::Draw() {
DrawSceneOutline(); DrawMainMenu();
DrawText("Gravity Surfing", 24, 28, 36, Color{230, 238, 255, 255}); Scene::Draw();
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});
} }