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

View File

@ -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"

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 "raylib.h"
#include "EnergyBarRaygui.hpp"
#include <algorithm>
std::shared_ptr<Entity> CreateProbe() {
auto e = std::make_shared<Entity>();
@ -13,7 +14,7 @@ std::shared_ptr<Entity> CreateProbe() {
e->AddComponent<GravityReceiverComponent>();
auto &physics = e->AddComponent<PhysicsComponent>();
physics.vx = 108.0f;
physics.vx = 16.0f;
physics.vy = 0.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 - 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<Entity> 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<Entity> CreateWorld() {
return e;
}
std::shared_ptr<Entity> CreateHUD() {
std::shared_ptr<Entity> CreateStats() {
auto e = std::make_shared<Entity>();
e->AddComponent<MeterComponent>();
e->AddComponent<HudComponent>();
e->AddComponent<StatsComponent>();
auto &render = e->AddComponent<RenderComponent>();
render.draw = [e]() {
auto meter = e->GetComponent<MeterComponent>();
if (!meter) {
auto stats = e->GetComponent<StatsComponent>();
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<int>((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;
}

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> CreateNullZone(float x, float width);
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;
/** @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;

View File

@ -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<ColliderComponent>();
@ -21,16 +21,13 @@ void CollectibleComponent::Setup() {
context->EmitCollectiblePicked(*entity);
entity->QueueFree();
if (!context->hudEntity) {
return;
if (context->statsEntity) {
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 "components/GravityWellComponent.hpp"
#include "components/MeterComponent.hpp"
#include "components/NullZoneComponent.hpp"
#include "components/PhysicsComponent.hpp"
#include "components/StatsComponent.hpp"
#include "components/TransformComponent.hpp"
#include <algorithm>
@ -32,18 +32,18 @@ void GravityReceiverComponent::Update(float dt) {
return;
}
MeterComponent *meterPtr = nullptr;
if (context->hudEntity) {
auto meter = context->hudEntity->GetComponent<MeterComponent>();
if (meter) {
meterPtr = &meter->get();
StatsComponent *statsPtr = nullptr;
if (context->statsEntity) {
auto stats = context->statsEntity->GetComponent<StatsComponent>();
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);
}
}

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 "components/GravityWellComponent.hpp"
#include "components/MeterComponent.hpp"
#include "components/NullZoneComponent.hpp"
#include "components/StatsComponent.hpp"
#include "components/TransformComponent.hpp"
#include <algorithm>
@ -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<MeterComponent>();
if (meter && meter->get().value <= 0.0f) {
if (context && entity == context->probeEntity && context->statsEntity) {
auto stats = context->statsEntity->GetComponent<StatsComponent>();
if (stats && stats->get().value <= 0.0f) {
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>
/**
* 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;
};

View File

@ -1,5 +1,6 @@
#include "Components.hpp"
#include "Draw.hpp"
#include "EnergyBarRaygui.hpp"
#include "Entities.hpp"
#include "Entity.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() {
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();
}

View File

@ -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<MeterComponent>();
if (meter) {
meterValue = meter->get().value;
if (context.statsEntity) {
auto stats = context.statsEntity->GetComponent<StatsComponent>();
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<std::reference_wrapper<ScrollComponent>> worldScroll;
if (context.worldEntity) {
worldScroll = context.worldEntity->GetComponent<ScrollComponent>();
@ -77,28 +75,5 @@ void GameplayScene::Draw() {
probeTransform = context.probeEntity->GetComponent<TransformComponent>();
}
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<RenderComponent>();
if (render) {
render->get().Draw();
}
}
Scene::Draw();
}

View File

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

View File

@ -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<std::shared_ptr<Entity>> 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<RenderComponent>();
if (render) {
render->get().Draw();
}
}
}
protected:
SceneManager &manager;

View File

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