Add black hole and stuff

master
John Montagu, the 4th Earl of Sandvich 2026-03-16 13:03:53 -07:00
parent fb506f6f05
commit bd622d1873
Signed by: sandvich
GPG Key ID: 9A39BE37E602B22D
17 changed files with 244 additions and 121 deletions

View File

@ -8,6 +8,7 @@
#include "components/LifetimeComponent.hpp" #include "components/LifetimeComponent.hpp"
#include "components/NullZoneComponent.hpp" #include "components/NullZoneComponent.hpp"
#include "components/PhysicsComponent.hpp" #include "components/PhysicsComponent.hpp"
#include "components/PlayerBlackHoleComponent.hpp"
#include "components/ProbeStateComponent.hpp" #include "components/ProbeStateComponent.hpp"
#include "components/ProjectionComponent.hpp" #include "components/ProjectionComponent.hpp"
#include "components/RenderComponent.hpp" #include "components/RenderComponent.hpp"

View File

@ -34,13 +34,21 @@ inline void DrawMainMenu() {
"GRAVITY SURFING"); "GRAVITY SURFING");
GuiLabel((Rectangle){WINDOW_WIDTH / 2 - 200, WINDOW_HEIGHT / 2, 400, 60}, GuiLabel((Rectangle){WINDOW_WIDTH / 2 - 200, WINDOW_HEIGHT / 2, 400, 60},
"LEFT CLICK to turn on gravity well and attract probe\n" "LEFT CLICK to place a black hole that lasts 1 second\n"
"Avoid hazards and collect stars to keep your meter from draining\n" "Each black hole costs 10 meter and does not drain over time\n"
"If your meter runs out, gravity well turns off and you lose control\n" "Avoid hazards and collect stars to refill meter\n"
"until you collect another star\n" "Place as many black holes as your meter allows\n"
"Press SPACE or LEFT CLICK to start"); "Press SPACE or LEFT CLICK to start");
} }
inline void DrawDeathStats(int stars) {
GuiLabel((Rectangle){WINDOW_WIDTH / 2 - 150, WINDOW_HEIGHT / 2 - 40, 300, 32}, "YOU DIED");
GuiLabel((Rectangle){WINDOW_WIDTH / 2 - 150, WINDOW_HEIGHT / 2 - 4, 300, 24},
TextFormat("Stars Collected: %d", stars));
GuiLabel((Rectangle){WINDOW_WIDTH / 2 - 150, WINDOW_HEIGHT / 2 + 28, 300, 20},
"Press ENTER or LEFT CLICK to retry");
}
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Controls Functions Definitions (local) // Controls Functions Definitions (local)
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------

View File

@ -3,6 +3,7 @@
#include "Components.hpp" #include "Components.hpp"
#include "EnergyBarRaygui.hpp" #include "EnergyBarRaygui.hpp"
#include "raylib.h"
#include <algorithm> #include <algorithm>
std::shared_ptr<Entity> CreateProbe() { std::shared_ptr<Entity> CreateProbe() {
@ -54,19 +55,8 @@ std::shared_ptr<Entity> CreateGravityWell() {
transform.y = 230.0f; transform.y = 230.0f;
auto &well = e->AddComponent<GravityWellComponent>(); auto &well = e->AddComponent<GravityWellComponent>();
well.mass = static_cast<float>(1 << 22); well.mass = 0.0f;
well.minDist = 28.0f; well.minDist = 28.0f;
well.followLerp = 12.0f;
auto &render = e->AddComponent<RenderComponent>();
render.draw = [e]() {
auto transform = e->GetComponent<TransformComponent>();
if (!transform) {
return;
}
DrawCircleLines(static_cast<int>(transform->get().x), static_cast<int>(transform->get().y),
18.0f, Color{86, 197, 255, 255});
};
return e; return e;
} }
@ -85,6 +75,8 @@ std::shared_ptr<Entity> CreateBlackHole(float x, float y) {
well.controlledByMouse = false; well.controlledByMouse = false;
well.alwaysActive = true; well.alwaysActive = true;
// shader removed: previously used for black hole lensing
auto &collider = e->AddComponent<ColliderComponent>(); auto &collider = e->AddComponent<ColliderComponent>();
collider.radius = 18.0f; collider.radius = 18.0f;
@ -107,6 +99,52 @@ std::shared_ptr<Entity> CreateBlackHole(float x, float y) {
return e; return e;
} }
std::shared_ptr<Entity> CreatePlayerBlackHole(float worldX, float y, float scrollX, float ttl) {
auto e = std::make_shared<Entity>();
auto &transform = e->AddComponent<TransformComponent>();
transform.x = worldX - scrollX;
transform.y = y;
auto &scrollable = e->AddComponent<ScrollableComponent>();
scrollable.worldX = worldX;
auto &well = e->AddComponent<GravityWellComponent>();
well.mass = static_cast<float>(1 << 22);
well.minDist = 28.0f;
well.controlledByMouse = false;
well.alwaysActive = true;
// shader removed: previously used for black hole lensing
auto &lifetime = e->AddComponent<LifetimeComponent>();
lifetime.remaining = ttl;
// Mark this as a player-created black hole so it can be removed via right-click
e->AddComponent<PlayerBlackHoleComponent>();
auto &render = e->AddComponent<RenderComponent>();
render.draw = [e]() {
auto transform = e->GetComponent<TransformComponent>();
if (!transform) {
return;
}
auto lifetime = e->GetComponent<LifetimeComponent>();
if (!lifetime) {
return;
}
const int cx = static_cast<int>(transform->get().x);
const int cy = static_cast<int>(transform->get().y);
float t = 360 * lifetime->get().remaining / 1;
DrawCircleSector({(float)cx, (float)cy}, 28.0f, 0.0f, t, 32, Color{70, 95, 170, 25});
DrawCircleLines(cx, cy, 18.0f, Color{70, 95, 170, 240});
DrawCircleLines(cx, cy, 24.0f, Color{95, 120, 200, 120});
};
return e;
}
std::shared_ptr<Entity> CreateStar(float x, float y) { std::shared_ptr<Entity> CreateStar(float x, float y) {
auto e = std::make_shared<Entity>(); auto e = std::make_shared<Entity>();
auto &t = e->AddComponent<TransformComponent>(); auto &t = e->AddComponent<TransformComponent>();
@ -115,7 +153,7 @@ std::shared_ptr<Entity> CreateStar(float x, float y) {
auto &scrollable = e->AddComponent<ScrollableComponent>(); auto &scrollable = e->AddComponent<ScrollableComponent>();
scrollable.worldX = x; scrollable.worldX = x;
auto &collider = e->AddComponent<ColliderComponent>(); auto &collider = e->AddComponent<ColliderComponent>();
collider.radius = 12.0f; collider.radius = 20.0f;
e->AddComponent<CollectibleComponent>(); e->AddComponent<CollectibleComponent>();
auto &render = e->AddComponent<RenderComponent>(); auto &render = e->AddComponent<RenderComponent>();
@ -126,9 +164,10 @@ std::shared_ptr<Entity> CreateStar(float x, float y) {
} }
Vector2 center = {transform->get().x, transform->get().y}; Vector2 center = {transform->get().x, transform->get().y};
Color STAR_COLOR = Color{255, 223, 86, 255}; Color STAR_COLOR = Color{255, 223, 86, 255};
Color GLOW_COLOR = Color{255, 223, 86, 120}; Color GLOW_COLOR = Color{255, 223, 86, 80};
DrawCircleV(center, 12.0f, GLOW_COLOR); DrawCircleV(center, 20.0f, GLOW_COLOR);
DrawPoly(center, 3, 4.0f, transform->get().x, STAR_COLOR); DrawPoly(center, 3, 10.0f, transform->get().x, STAR_COLOR);
DrawPoly(center, 3, 10.0f, transform->get().x + 180, STAR_COLOR);
}; };
return e; return e;
} }

View File

@ -7,6 +7,8 @@
std::shared_ptr<Entity> CreateProbe(); std::shared_ptr<Entity> CreateProbe();
std::shared_ptr<Entity> CreateGravityWell(); std::shared_ptr<Entity> CreateGravityWell();
std::shared_ptr<Entity> CreateBlackHole(float x, float y); std::shared_ptr<Entity> CreateBlackHole(float x, float y);
std::shared_ptr<Entity> CreatePlayerBlackHole(float worldX, float y, float scrollX,
float ttl = 1.0f);
std::shared_ptr<Entity> CreateStar(float x, float y); std::shared_ptr<Entity> CreateStar(float x, float y);
std::shared_ptr<Entity> CreateAsteroid(float x, float y); 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);

View File

@ -4,7 +4,6 @@
#include "components/GravityWellComponent.hpp" #include "components/GravityWellComponent.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>
@ -17,33 +16,9 @@ void GravityReceiverComponent::Update(float dt) {
return; return;
} }
if (!well && context->wellEntity) {
well = context->wellEntity;
}
if (!well) {
return;
}
auto myTransform = entity->GetComponent<TransformComponent>(); auto myTransform = entity->GetComponent<TransformComponent>();
auto physics = entity->GetComponent<PhysicsComponent>(); auto physics = entity->GetComponent<PhysicsComponent>();
auto wellTransform = well->GetComponent<TransformComponent>(); if (!myTransform || !physics) {
auto wellGravity = well->GetComponent<GravityWellComponent>();
if (!myTransform || !physics || !wellTransform || !wellGravity) {
return;
}
StatsComponent *statsPtr = nullptr;
if (context->statsEntity) {
auto stats = context->statsEntity->GetComponent<StatsComponent>();
if (stats) {
statsPtr = &stats->get();
}
}
if (!wellGravity->get().active) {
return;
}
if (statsPtr && statsPtr->value <= 0.0f) {
return; return;
} }
@ -72,23 +47,35 @@ void GravityReceiverComponent::Update(float dt) {
return; return;
} }
const float dx = wellTransform->get().x - myTransform->get().x; if (!context->entities) {
const float dy = wellTransform->get().y - myTransform->get().y;
const float dist = std::sqrt(dx * dx + dy * dy);
if (dist <= 0.0001f) {
return; return;
} }
const float clampedDist = std::max(dist, wellGravity->get().minDist); for (auto &other : *context->entities) {
const float force = wellGravity->get().mass / (clampedDist * clampedDist); if (!other || other.get() == entity) {
const float nx = dx / dist; continue;
const float ny = dy / dist; }
physics->get().vx += nx * force * dt; auto wellTransform = other->GetComponent<TransformComponent>();
physics->get().vy += ny * force * dt; auto wellGravity = other->GetComponent<GravityWellComponent>();
if (!wellTransform || !wellGravity || !wellGravity->get().active) {
continue;
}
if (statsPtr) { const float dx = wellTransform->get().x - myTransform->get().x;
statsPtr->Drain(statsPtr->drainRate * dt); const float dy = wellTransform->get().y - myTransform->get().y;
const float dist = std::sqrt(dx * dx + dy * dy);
if (dist <= 0.0001f) {
continue;
}
const float clampedDist = std::max(dist, wellGravity->get().minDist);
const float force = wellGravity->get().mass / (clampedDist * clampedDist);
const float nx = dx / dist;
const float ny = dy / dist;
physics->get().vx += nx * force * dt;
physics->get().vy += ny * force * dt;
} }
} }

View File

@ -3,15 +3,9 @@
#include "Component.hpp" #include "Component.hpp"
/** /**
* Applies gravity well force to the probe and drains meter while active. * Applies gravity from active wells to the probe.
*/ */
struct GravityReceiverComponent : public Component { struct GravityReceiverComponent : public Component {
/**
* The gravity well entity that this receiver is affected by. If null, the receiver will not
* apply any forces.
*/
Entity *well = nullptr;
/** /**
* Whether the probe is inside a void zone, which disables the well's gravity. * Whether the probe is inside a void zone, which disables the well's gravity.
*/ */

View File

@ -1,32 +1,58 @@
#include "components/GravityWellComponent.hpp" #include "components/GravityWellComponent.hpp"
#include "Entities.hpp"
#include "Entity.hpp" #include "Entity.hpp"
#include "components/TransformComponent.hpp" #include "components/PlayerBlackHoleComponent.hpp"
#include "components/StatsComponent.hpp"
#include "raylib.h" #include "raylib.h"
#include <algorithm>
void GravityWellComponent::Setup() {} void GravityWellComponent::Setup() {}
void GravityWellComponent::Update(float dt) { void GravityWellComponent::Update(float) {
auto transform = entity->GetComponent<TransformComponent>();
if (!transform) {
return;
}
if (!controlledByMouse) { if (!controlledByMouse) {
active = alwaysActive; active = alwaysActive;
return; return;
} }
active = IsMouseButtonDown(MOUSE_BUTTON_LEFT); active = false;
if (!context || !context->entities) {
return;
}
// Right click removes all player-created black holes
if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) {
for (auto &ent : *context->entities) {
if (!ent || ent->queuedForFree) {
continue;
}
auto marker = ent->GetComponent<PlayerBlackHoleComponent>();
if (marker) {
ent->QueueFree();
}
}
// Do not early return; allow left-click placement to still happen in the same frame
}
if (!IsMouseButtonPressed(MOUSE_BUTTON_LEFT) || !context->statsEntity) {
return;
}
auto stats = context->statsEntity->GetComponent<StatsComponent>();
if (!stats || stats->get().value < placementCost) {
return;
}
stats->get().Drain(placementCost);
const Vector2 mouse = GetMousePosition(); const Vector2 mouse = GetMousePosition();
auto &t = transform->get(); const float worldX = context->scrollX + mouse.x;
const float blend = std::clamp(followLerp * dt, 0.0f, 1.0f);
t.x += (mouse.x - t.x) * blend; auto blackHole = CreatePlayerBlackHole(worldX, mouse.y, context->scrollX, placementTtl);
t.y += (mouse.y - t.y) * blend; blackHole->SetContext(context);
context->entities->push_back(blackHole);
} }
void GravityWellComponent::Cleanup() {} void GravityWellComponent::Cleanup() {}

View File

@ -3,7 +3,7 @@
#include "Component.hpp" #include "Component.hpp"
/** /**
* Represents player-controlled gravity source that follows mouse input. * Handles gravity well behavior for both hazards and player-spawned black holes.
*/ */
struct GravityWellComponent : public Component { struct GravityWellComponent : public Component {
/** /**
@ -18,13 +18,12 @@ struct GravityWellComponent : public Component {
float minDist = 30.0f; float minDist = 30.0f;
/** /**
* Whether the gravity well is currently active and should apply gravitational forces to * Whether the gravity source is currently active and should apply gravitational force.
* receivers (e.g. tied to mouse button state).
*/ */
bool active = false; bool active = false;
/** /**
* If true, active state is driven by left mouse button and this well follows the cursor. * If true, this component is used as the player input controller.
*/ */
bool controlledByMouse = true; bool controlledByMouse = true;
@ -34,9 +33,14 @@ struct GravityWellComponent : public Component {
bool alwaysActive = false; bool alwaysActive = false;
/** /**
* Lerp factor for how quickly the gravity well follows the mouse position. * Meter cost paid to place one player black hole.
*/ */
float followLerp = 12.0f; float placementCost = 10.0f;
/**
* Lifetime in seconds for each player-placed black hole.
*/
float placementTtl = 1.0f;
void Setup() override; void Setup() override;
void Update(float dt) override; void Update(float dt) override;

View File

@ -100,7 +100,7 @@ bool PhysicsComponent::ComputeGravityDeltaVelocity(double px, double py, double
continue; continue;
} }
if (probeMeterDepleted && wellGravity->get().controlledByMouse) { if (probeMeterDepleted && !wellGravity->get().alwaysActive) {
continue; continue;
} }

View File

@ -0,0 +1,13 @@
#pragma once
#include "Component.hpp"
/**
* Marker component to identify player-created black holes. It carries no
* behavior and is only used for runtime identification and removal.
*/
struct PlayerBlackHoleComponent : public Component {
void Setup() override {}
void Update(float) override {}
void Cleanup() override {}
};

View File

@ -1,11 +1,14 @@
#include "components/ProjectionComponent.hpp" #include "components/ProjectionComponent.hpp"
#include "Entity.hpp" #include "Entity.hpp"
#include "components/GravityReceiverComponent.hpp"
#include "components/GravityWellComponent.hpp" #include "components/GravityWellComponent.hpp"
#include "components/PhysicsComponent.hpp" #include "components/PhysicsComponent.hpp"
#include "components/StatsComponent.hpp"
#include "components/TransformComponent.hpp" #include "components/TransformComponent.hpp"
#include <algorithm>
#include <cmath>
void ProjectionComponent::Setup() { points.clear(); } void ProjectionComponent::Setup() { points.clear(); }
void ProjectionComponent::Update(float) { void ProjectionComponent::Update(float) {
@ -18,25 +21,45 @@ void ProjectionComponent::Update(float) {
auto transform = entity->GetComponent<TransformComponent>(); auto transform = entity->GetComponent<TransformComponent>();
auto physics = entity->GetComponent<PhysicsComponent>(); auto physics = entity->GetComponent<PhysicsComponent>();
auto receiver = entity->GetComponent<GravityReceiverComponent>(); if (!transform || !physics || !context->entities) {
if (!transform || !physics || !receiver) {
return; return;
} }
Entity *wellEntity = receiver->get().well ? receiver->get().well : context->wellEntity; float placementCost = 10.0f;
if (!wellEntity) { float previewMass = static_cast<float>(1 << 22);
return; float previewMinDist = 28.0f;
if (context->wellEntity) {
auto controllerWell = context->wellEntity->GetComponent<GravityWellComponent>();
if (controllerWell) {
placementCost = controllerWell->get().placementCost;
if (controllerWell->get().mass > 0.0f) {
previewMass = controllerWell->get().mass;
}
previewMinDist = controllerWell->get().minDist;
}
} }
auto wellTransform = wellEntity->GetComponent<TransformComponent>(); bool canPreviewPlacement = false;
auto wellGravity = wellEntity->GetComponent<GravityWellComponent>(); if (context->statsEntity) {
if (!wellTransform || !wellGravity) { auto stats = context->statsEntity->GetComponent<StatsComponent>();
return; canPreviewPlacement = stats && stats->get().value >= placementCost;
} }
// only highlight if the well is active, inactive will be a lighter color to show the potential const Vector2 mouse = GetMousePosition();
// projection if the player were to activate it const double previewX = static_cast<double>(mouse.x);
highlightActive = wellGravity->get().active; const double previewY = static_cast<double>(mouse.y);
for (auto &other : *context->entities) {
if (!other || other.get() == entity) {
continue;
}
auto wellGravity = other->GetComponent<GravityWellComponent>();
if (wellGravity && wellGravity->get().active) {
highlightActive = true;
break;
}
}
double px = static_cast<double>(transform->get().x); double px = static_cast<double>(transform->get().x);
double py = static_cast<double>(transform->get().y); double py = static_cast<double>(transform->get().y);
@ -46,6 +69,21 @@ void ProjectionComponent::Update(float) {
points.reserve(static_cast<size_t>(steps)); points.reserve(static_cast<size_t>(steps));
for (int i = 0; i < steps; ++i) { for (int i = 0; i < steps; ++i) {
physics->get().SimulateStep(px, py, vx, vy, static_cast<double>(stepDt), true); physics->get().SimulateStep(px, py, vx, vy, static_cast<double>(stepDt), true);
if (canPreviewPlacement && !physics->get().IsInsideNullZone(px)) {
const double dx = previewX - px;
const double dy = previewY - py;
const double dist = std::sqrt(dx * dx + dy * dy);
if (dist > 0.0001) {
const double clampedDist = std::max(dist, static_cast<double>(previewMinDist));
const double force = static_cast<double>(previewMass) / (clampedDist * clampedDist);
const double dt = static_cast<double>(stepDt);
vx += (dx / dist) * force * dt;
vy += (dy / dist) * force * dt;
physics->get().ClampVelocity(vx, vy);
}
}
points.push_back({static_cast<float>(px), static_cast<float>(py)}); points.push_back({static_cast<float>(px), static_cast<float>(py)});
} }

View File

@ -33,12 +33,12 @@ void SpawnComponent::Update(float) {
while (cursorWX < spawnLimit) { while (cursorWX < spawnLimit) {
const float r = static_cast<float>(GetRandomValue(0, 99)); const float r = static_cast<float>(GetRandomValue(0, 99));
if (r < 50.0f) { if (r < 70.0f) {
const float y = static_cast<float>(GetRandomValue(48, GetScreenHeight() - 48)); const float y = static_cast<float>(GetRandomValue(48, GetScreenHeight() - 48));
auto star = CreateStar(cursorWX, y); auto star = CreateStar(cursorWX, y);
star->SetContext(context); star->SetContext(context);
context->entities->push_back(star); context->entities->push_back(star);
} else if (r < 78.0f) { } else if (r < 90.0f) {
const float y = static_cast<float>(GetRandomValue(42, GetScreenHeight() - 42)); const float y = static_cast<float>(GetRandomValue(42, GetScreenHeight() - 42));
auto asteroid = CreateAsteroid(cursorWX, y); auto asteroid = CreateAsteroid(cursorWX, y);
asteroid->SetContext(context); asteroid->SetContext(context);

View File

@ -10,8 +10,8 @@
struct StatsComponent : 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 = 10.0f;
float gainPerStar = 28.0f; float gainPerStar = 50.0f;
int stars = 0; int stars = 0;
void Setup() override; void Setup() override;

View File

@ -1,5 +1,6 @@
#include "scene/DeathScene.hpp" #include "scene/DeathScene.hpp"
#include "EnergyBarRaygui.hpp"
#include "scene/GameplayScene.hpp" #include "scene/GameplayScene.hpp"
#include "scene/SceneManager.hpp" #include "scene/SceneManager.hpp"
#include "scene/StartMenuScene.hpp" #include "scene/StartMenuScene.hpp"
@ -17,4 +18,7 @@ void DeathScene::Update(float) {
void DeathScene::Draw() { void DeathScene::Draw() {
Scene::Draw(); Scene::Draw();
// Draw centered death stats using the HUD helper
// collectedStars is a private member; access via this-> to satisfy older compilers / linters
DrawDeathStats(this->collectedStars);
} }

View File

@ -14,6 +14,11 @@ class StartMenuScene;
class DeathScene : public Scene { class DeathScene : public Scene {
public: public:
explicit DeathScene(SceneManager &owner) : Scene(owner) {} explicit DeathScene(SceneManager &owner) : Scene(owner) {}
// Alternate constructor that accepts the star count to display.
explicit DeathScene(SceneManager &owner, int stars) : Scene(owner), collectedStars(stars) {}
void Update(float dt) override; void Update(float dt) override;
void Draw() override; void Draw() override;
private:
int collectedStars = 0;
}; };

View File

@ -4,17 +4,23 @@
#include "scene/DeathScene.hpp" #include "scene/DeathScene.hpp"
#include "scene/SceneManager.hpp" #include "scene/SceneManager.hpp"
#include <algorithm>
void GameplayScene::Enter() { void GameplayScene::Enter() {
entities.clear(); entities.clear();
entities.reserve(20); entities.reserve(20);
context = {}; context = {};
wantsDeathScene = false;
collectedCount = 0; collectedCount = 0;
meterValue = 60.0f; meterValue = 60.0f;
context.onPlayerDeath = [this]() { wantsDeathScene = true; }; context.onPlayerDeath = [this]() {
// Inject the collected star count into the queued DeathScene by passing it
// as a constructor argument. SceneManager::QueueSceneChange supports
// forwarding constructor args.
manager.QueueSceneChange<DeathScene>(collectedCount);
};
context.AddCollectiblePickedListener([this](Entity &collectible) { context.AddCollectiblePickedListener([this](Entity &collectible) {
++collectedCount; collectedCount++;
auto transform = collectible.GetComponent<TransformComponent>(); auto transform = collectible.GetComponent<TransformComponent>();
if (!transform || !context.entities) { if (!transform || !context.entities) {
@ -56,23 +62,19 @@ void GameplayScene::Enter() {
} }
} }
void GameplayScene::Update(float dt) { void GameplayScene::Exit() { entities.clear(); }
UpdateAllSystems(entities, dt);
if (wantsDeathScene) { void GameplayScene::Update(float dt) { UpdateAllSystems(entities, dt); }
manager.QueueSceneChange<DeathScene>();
}
}
void GameplayScene::Draw() { void GameplayScene::Draw() {
std::optional<std::reference_wrapper<ScrollComponent>> worldScroll; for (auto &entity : entities) {
if (context.worldEntity) { if (!entity || entity->queuedForFree) {
worldScroll = context.worldEntity->GetComponent<ScrollComponent>(); continue;
} }
auto render = entity->GetComponent<RenderComponent>();
std::optional<std::reference_wrapper<TransformComponent>> probeTransform; if (render) {
if (context.probeEntity) { render->get().Draw();
probeTransform = context.probeEntity->GetComponent<TransformComponent>(); }
} }
Scene::Draw(); Scene::Draw();

View File

@ -21,12 +21,12 @@ class GameplayScene : public Scene {
public: public:
explicit GameplayScene(SceneManager &owner) : Scene(owner) {} explicit GameplayScene(SceneManager &owner) : Scene(owner) {}
void Enter() override; void Enter() override;
void Exit() override;
void Update(float dt) override; void Update(float dt) override;
void Draw() override; void Draw() override;
private: private:
GameContext context; GameContext context;
bool wantsDeathScene = false;
int collectedCount = 0; int collectedCount = 0;
float meterValue = 60.0f; float meterValue = 60.0f;
}; };