Refactor game loop to use state machine scene manager
parent
7e954cd4de
commit
3bf8200d0f
|
|
@ -8,6 +8,7 @@
|
|||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
struct TransformComponent : public Component {
|
||||
float x = 0.0f;
|
||||
|
|
@ -85,6 +86,19 @@ struct MeterComponent : public Component {
|
|||
float drainRate = 14.0f;
|
||||
float gainPerStar = 28.0f;
|
||||
void Setup() override {}
|
||||
|
||||
void SetValue(float newValue) {
|
||||
const float oldValue = value;
|
||||
value = newValue;
|
||||
if (context && oldValue != value) {
|
||||
context->EmitMeterChanged(oldValue, value);
|
||||
}
|
||||
}
|
||||
|
||||
void AddValue(float delta) { SetValue(std::clamp(value + delta, 0.0f, maxValue)); }
|
||||
|
||||
void Drain(float amount) { AddValue(-amount); }
|
||||
|
||||
void Update(float) override {}
|
||||
void Cleanup() override {}
|
||||
};
|
||||
|
|
@ -98,7 +112,19 @@ struct NullZoneComponent : public Component {
|
|||
|
||||
struct ColliderComponent : public Component {
|
||||
float radius = 8.0f;
|
||||
std::vector<std::function<void(Entity &)>> onCollision;
|
||||
void Setup() override {}
|
||||
|
||||
void EmitCollision(Entity &other) {
|
||||
for (auto &callback : onCollision) {
|
||||
callback(other);
|
||||
}
|
||||
}
|
||||
|
||||
void AddCollisionListener(std::function<void(Entity &)> callback) {
|
||||
onCollision.push_back(std::move(callback));
|
||||
}
|
||||
|
||||
void Update(float) override {}
|
||||
void Cleanup() override {}
|
||||
};
|
||||
|
|
@ -142,66 +168,57 @@ struct ProjectionComponent : public Component {
|
|||
|
||||
struct CollectibleComponent : public Component {
|
||||
bool collected = false;
|
||||
void Setup() override {}
|
||||
void Update(float) override {
|
||||
if (collected || !context || !context->probeEntity || entity == context->probeEntity) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto selfTransform = entity->GetComponent<TransformComponent>();
|
||||
void Setup() override {
|
||||
auto selfCollider = entity->GetComponent<ColliderComponent>();
|
||||
auto probeTransform = context->probeEntity->GetComponent<TransformComponent>();
|
||||
auto probeCollider = context->probeEntity->GetComponent<ColliderComponent>();
|
||||
if (!selfTransform || !selfCollider || !probeTransform || !probeCollider) {
|
||||
if (!selfCollider) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float dx = selfTransform->get().x - probeTransform->get().x;
|
||||
const float dy = selfTransform->get().y - probeTransform->get().y;
|
||||
const float r = selfCollider->get().radius + probeCollider->get().radius;
|
||||
if ((dx * dx + dy * dy) > (r * r)) {
|
||||
return;
|
||||
}
|
||||
selfCollider->get().AddCollisionListener([this](Entity &other) {
|
||||
if (collected || !context || !context->probeEntity || &other != context->probeEntity) {
|
||||
return;
|
||||
}
|
||||
|
||||
collected = true;
|
||||
collected = true;
|
||||
context->EmitCollectiblePicked(*entity);
|
||||
|
||||
if (!context->hudEntity) {
|
||||
return;
|
||||
}
|
||||
if (!context->hudEntity) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto meter = context->hudEntity->GetComponent<MeterComponent>();
|
||||
if (!meter) {
|
||||
return;
|
||||
}
|
||||
auto meter = context->hudEntity->GetComponent<MeterComponent>();
|
||||
if (!meter) {
|
||||
return;
|
||||
}
|
||||
|
||||
meter->get().value =
|
||||
std::min(meter->get().maxValue, meter->get().value + meter->get().gainPerStar);
|
||||
meter->get().AddValue(meter->get().gainPerStar);
|
||||
});
|
||||
}
|
||||
|
||||
void Update(float) override {}
|
||||
|
||||
void Cleanup() override {}
|
||||
};
|
||||
|
||||
struct HazardComponent : public Component {
|
||||
void Setup() override {}
|
||||
void Update(float) override {
|
||||
if (!context || !context->probeEntity || entity == context->probeEntity) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto selfTransform = entity->GetComponent<TransformComponent>();
|
||||
void Setup() override {
|
||||
auto selfCollider = entity->GetComponent<ColliderComponent>();
|
||||
auto probeTransform = context->probeEntity->GetComponent<TransformComponent>();
|
||||
auto probeCollider = context->probeEntity->GetComponent<ColliderComponent>();
|
||||
if (!selfTransform || !selfCollider || !probeTransform || !probeCollider) {
|
||||
if (!selfCollider) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float dx = selfTransform->get().x - probeTransform->get().x;
|
||||
const float dy = selfTransform->get().y - probeTransform->get().y;
|
||||
const float r = selfCollider->get().radius + probeCollider->get().radius;
|
||||
if ((dx * dx + dy * dy) <= (r * r)) {
|
||||
context->resetRequested = true;
|
||||
}
|
||||
selfCollider->get().AddCollisionListener([this](Entity &other) {
|
||||
if (!context || !context->probeEntity || &other != context->probeEntity) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->onPlayerDeath) {
|
||||
context->onPlayerDeath();
|
||||
}
|
||||
});
|
||||
}
|
||||
void Update(float) override {}
|
||||
void Cleanup() override {}
|
||||
};
|
||||
|
||||
|
|
@ -285,7 +302,7 @@ struct GravityReceiverComponent : public Component {
|
|||
physics->get().vy += ny * force * dt;
|
||||
|
||||
if (meterPtr) {
|
||||
meterPtr->value = std::max(0.0f, meterPtr->value - meterPtr->drainRate * dt);
|
||||
meterPtr->Drain(meterPtr->drainRate * dt);
|
||||
}
|
||||
}
|
||||
void Cleanup() override {}
|
||||
|
|
@ -296,7 +313,6 @@ struct ProbeStateComponent : public Component {
|
|||
float spawnY = 230.0f;
|
||||
float spawnVx = 165.0f;
|
||||
float spawnVy = 0.0f;
|
||||
|
||||
void Setup() override {}
|
||||
void Update(float) override {
|
||||
if (!context || !context->probeEntity || entity != context->probeEntity) {
|
||||
|
|
@ -304,47 +320,17 @@ struct ProbeStateComponent : public Component {
|
|||
}
|
||||
|
||||
auto transform = entity->GetComponent<TransformComponent>();
|
||||
auto physics = entity->GetComponent<PhysicsComponent>();
|
||||
if (!transform || !physics) {
|
||||
if (!transform) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (transform->get().y < -20.0f ||
|
||||
transform->get().y > static_cast<float>(GetScreenHeight() + 20) ||
|
||||
transform->get().x < -20.0f) {
|
||||
context->resetRequested = true;
|
||||
}
|
||||
|
||||
if (!context->resetRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
transform->get().x = spawnX;
|
||||
transform->get().y = spawnY;
|
||||
physics->get().vx = spawnVx;
|
||||
physics->get().vy = spawnVy;
|
||||
|
||||
if (context->hudEntity) {
|
||||
auto meter = context->hudEntity->GetComponent<MeterComponent>();
|
||||
if (meter) {
|
||||
meter->get().value = 60.0f;
|
||||
if (context->onPlayerDeath) {
|
||||
context->onPlayerDeath();
|
||||
}
|
||||
}
|
||||
|
||||
if (context->entities) {
|
||||
for (auto &other : *context->entities) {
|
||||
if (!other) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto collectible = other->GetComponent<CollectibleComponent>();
|
||||
if (collectible) {
|
||||
collectible->get().collected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context->resetRequested = false;
|
||||
}
|
||||
void Cleanup() override {}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,50 +1,79 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
struct Entity;
|
||||
|
||||
/**
|
||||
* Shared execution context that flows through every entity and component so
|
||||
* they can read/write the global scroll, known entity handles, and reset state.
|
||||
* Shared state for one gameplay scene instance.
|
||||
*/
|
||||
struct GameContext {
|
||||
/**
|
||||
* Pointer to the global entity list stored in `main.cpp`, allowing systems
|
||||
* or components to inspect/create entities.
|
||||
* @brief Pointer to the entity list owned by the active gameplay scene.
|
||||
*/
|
||||
std::vector<std::shared_ptr<Entity>> *entities = nullptr;
|
||||
|
||||
/**
|
||||
* Entity that owns the static world geometry (terrain, background, etc.).
|
||||
*/
|
||||
/** @brief World entity (scroll/spawn owner). */
|
||||
Entity *worldEntity = nullptr;
|
||||
|
||||
/**
|
||||
* Entity representing the gravity well that drags collectibles/probe.
|
||||
*/
|
||||
/** @brief Gravity well entity. */
|
||||
Entity *wellEntity = nullptr;
|
||||
|
||||
/**
|
||||
* Entity for the player's probe input/state representation.
|
||||
*/
|
||||
/** @brief Player probe entity. */
|
||||
Entity *probeEntity = nullptr;
|
||||
|
||||
/**
|
||||
* HUD entity that draws meter/score/probe status overlays.
|
||||
*/
|
||||
/** @brief HUD entity. */
|
||||
Entity *hudEntity = nullptr;
|
||||
|
||||
/**
|
||||
* Global horizontal scroll offset that components read to position
|
||||
* themselves on screen.
|
||||
*/
|
||||
/** @brief Shared horizontal world scroll value. */
|
||||
float scrollX = 0.0f;
|
||||
|
||||
/** @brief Optional callback invoked when the probe dies. */
|
||||
std::function<void()> onPlayerDeath;
|
||||
|
||||
/** @brief Callbacks fired whenever a collectible is picked up. */
|
||||
std::vector<std::function<void(Entity &)>> collectiblePickedListeners;
|
||||
|
||||
/** @brief Callbacks fired whenever meter value changes. */
|
||||
std::vector<std::function<void(float, float)>> meterChangedListeners;
|
||||
|
||||
/**
|
||||
* Flag that a component (usually reset button) can toggle to request the
|
||||
* gameplay systems reset the probe/meter/collectibles.
|
||||
* Registers a collectible pickup listener.
|
||||
*
|
||||
* @param listener Callback receiving the collected entity.
|
||||
*/
|
||||
bool resetRequested = false;
|
||||
void AddCollectiblePickedListener(std::function<void(Entity &)> listener) {
|
||||
collectiblePickedListeners.push_back(std::move(listener));
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits collectible pickup event.
|
||||
*
|
||||
* @param collectible The collected entity.
|
||||
*/
|
||||
void EmitCollectiblePicked(Entity &collectible) {
|
||||
for (auto &listener : collectiblePickedListeners) {
|
||||
listener(collectible);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a meter changed listener.
|
||||
*
|
||||
* @param listener Callback receiving old value then new value.
|
||||
*/
|
||||
void AddMeterChangedListener(std::function<void(float, float)> listener) {
|
||||
meterChangedListeners.push_back(std::move(listener));
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits meter changed event.
|
||||
*
|
||||
* @param oldValue Meter value before mutation.
|
||||
* @param newValue Meter value after mutation.
|
||||
*/
|
||||
void EmitMeterChanged(float oldValue, float newValue) {
|
||||
for (auto &listener : meterChangedListeners) {
|
||||
listener(oldValue, newValue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,219 @@
|
|||
#pragma once
|
||||
|
||||
#include "Draw.hpp"
|
||||
#include "Entities.hpp"
|
||||
#include "Systems.hpp"
|
||||
|
||||
#include "raylib.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class SceneManager;
|
||||
|
||||
class Scene {
|
||||
public:
|
||||
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;
|
||||
|
||||
protected:
|
||||
SceneManager &manager;
|
||||
};
|
||||
|
||||
/**
|
||||
* Manages the current active scene, using an object oriented state machine approach.
|
||||
*/
|
||||
class SceneManager {
|
||||
public:
|
||||
/**
|
||||
* @brief Changes the current scene, invoking `Exit` on the old scene and `Enter`
|
||||
* on the new scene. The new scene is constructed in-place with the provided arguments.
|
||||
*
|
||||
* @tparam T The type of the new scene, must derive from `Scene`.
|
||||
* @param args Arguments forwarded to the constructor of the new scene.
|
||||
*/
|
||||
template <typename T, typename... Args> void ChangeScene(Args &&...args);
|
||||
|
||||
/**
|
||||
* @brief Changes to the provided next scene, invoking `Exit` on the old scene and
|
||||
* `Enter` on the new scene.
|
||||
*
|
||||
* @param nextScene The new scene to switch to.
|
||||
*/
|
||||
void ChangeScene(std::unique_ptr<Scene> nextScene);
|
||||
void Update(float dt);
|
||||
void Draw();
|
||||
|
||||
private:
|
||||
// use unique_ptr to enforce single ownership and ensure proper cleanup on
|
||||
// scene change
|
||||
std::unique_ptr<Scene> current;
|
||||
};
|
||||
|
||||
class StartMenuScene;
|
||||
class GameplayScene;
|
||||
class DeathScene;
|
||||
|
||||
class StartMenuScene : public Scene {
|
||||
public:
|
||||
explicit StartMenuScene(SceneManager &owner) : Scene(owner) {}
|
||||
void Update(float dt) override;
|
||||
void Draw() override;
|
||||
};
|
||||
|
||||
class GameplayScene : public Scene {
|
||||
public:
|
||||
explicit GameplayScene(SceneManager &owner) : Scene(owner) {}
|
||||
void Enter() override;
|
||||
void Update(float dt) override;
|
||||
void Draw() override;
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<Entity>> entities;
|
||||
GameContext context;
|
||||
bool wantsDeathScene = false;
|
||||
int collectedCount = 0;
|
||||
float meterValue = 60.0f;
|
||||
};
|
||||
|
||||
class DeathScene : public Scene {
|
||||
public:
|
||||
explicit DeathScene(SceneManager &owner) : Scene(owner) {}
|
||||
void Update(float dt) override;
|
||||
void Draw() override;
|
||||
};
|
||||
|
||||
inline void SceneManager::ChangeScene(std::unique_ptr<Scene> nextScene) {
|
||||
if (current) {
|
||||
current->Exit();
|
||||
}
|
||||
|
||||
current = std::move(nextScene);
|
||||
if (current) {
|
||||
current->Enter();
|
||||
}
|
||||
}
|
||||
|
||||
inline void SceneManager::Update(float dt) {
|
||||
if (current) {
|
||||
current->Update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
inline void SceneManager::Draw() {
|
||||
if (current) {
|
||||
current->Draw();
|
||||
}
|
||||
}
|
||||
|
||||
inline void StartMenuScene::Update(float) {
|
||||
if (IsKeyPressed(KEY_ENTER) || IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
|
||||
manager.ChangeScene<GameplayScene>();
|
||||
}
|
||||
}
|
||||
|
||||
inline 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});
|
||||
}
|
||||
|
||||
inline void GameplayScene::Enter() {
|
||||
entities.clear();
|
||||
entities.reserve(20);
|
||||
context = {};
|
||||
wantsDeathScene = false;
|
||||
collectedCount = 0;
|
||||
meterValue = 60.0f;
|
||||
|
||||
context.onPlayerDeath = [this]() { wantsDeathScene = true; };
|
||||
context.AddCollectiblePickedListener([this](Entity &) { ++collectedCount; });
|
||||
context.AddMeterChangedListener([this](float, float newValue) { meterValue = newValue; });
|
||||
|
||||
entities.push_back(CreateWorld());
|
||||
entities.push_back(CreateGravityWell());
|
||||
entities.push_back(CreateProbe());
|
||||
entities.push_back(CreateStar(900.0f, 120.0f));
|
||||
entities.push_back(CreateAsteroid(1100.0f, 330.0f));
|
||||
entities.push_back(CreateNullZone(1280.0f, 70.0f));
|
||||
entities.push_back(CreateHUD());
|
||||
|
||||
if (auto meter = entities.back()->GetComponent<MeterComponent>()) {
|
||||
meterValue = meter->get().value;
|
||||
}
|
||||
}
|
||||
|
||||
inline void GameplayScene::Update(float dt) {
|
||||
UpdateAllSystems(entities, context, dt);
|
||||
if (wantsDeathScene) {
|
||||
manager.ChangeScene<DeathScene>();
|
||||
}
|
||||
}
|
||||
|
||||
inline void GameplayScene::Draw() {
|
||||
DrawSceneOutline();
|
||||
DrawText("Gravity Surfing", 14, 12, 20, Color{230, 238, 255, 255});
|
||||
|
||||
auto worldScroll = entities[0]->GetComponent<ScrollComponent>();
|
||||
auto probeTransform = entities[2]->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) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto collectible = entity->GetComponent<CollectibleComponent>();
|
||||
if (collectible && collectible->get().collected) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto render = entity->GetComponent<RenderComponent>();
|
||||
if (render) {
|
||||
render->get().Draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void DeathScene::Update(float) {
|
||||
if (IsKeyPressed(KEY_ENTER) || IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
|
||||
manager.ChangeScene<GameplayScene>();
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KEY_ESCAPE)) {
|
||||
manager.ChangeScene<StartMenuScene>();
|
||||
}
|
||||
}
|
||||
|
||||
inline 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});
|
||||
}
|
||||
|
||||
template <typename T, typename... Args> inline void SceneManager::ChangeScene(Args &&...args) {
|
||||
ChangeScene(std::make_unique<T>(*this, std::forward<Args>(args)...));
|
||||
}
|
||||
|
|
@ -26,4 +26,38 @@ void UpdateAllSystems(std::vector<std::shared_ptr<Entity>> &entities, GameContex
|
|||
|
||||
entity->Update(deltaTime);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < entities.size(); ++i) {
|
||||
auto &a = entities[i];
|
||||
if (!a) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto aTransform = a->GetComponent<TransformComponent>();
|
||||
auto aCollider = a->GetComponent<ColliderComponent>();
|
||||
if (!aTransform || !aCollider) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t j = i + 1; j < entities.size(); ++j) {
|
||||
auto &b = entities[j];
|
||||
if (!b) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto bTransform = b->GetComponent<TransformComponent>();
|
||||
auto bCollider = b->GetComponent<ColliderComponent>();
|
||||
if (!bTransform || !bCollider) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const float dx = aTransform->get().x - bTransform->get().x;
|
||||
const float dy = aTransform->get().y - bTransform->get().y;
|
||||
const float r = aCollider->get().radius + bCollider->get().radius;
|
||||
if ((dx * dx + dy * dy) <= (r * r)) {
|
||||
aCollider->get().EmitCollision(*b);
|
||||
bCollider->get().EmitCollision(*a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
58
as6/main.cpp
58
as6/main.cpp
|
|
@ -3,6 +3,7 @@
|
|||
#include "Entities.hpp"
|
||||
#include "Entity.hpp"
|
||||
#include "GameContext.hpp"
|
||||
#include "SceneManager.hpp"
|
||||
#include "Systems.hpp"
|
||||
|
||||
#include "raylib-cpp.hpp"
|
||||
|
|
@ -12,67 +13,18 @@ int main() {
|
|||
window.SetState(FLAG_WINDOW_RESIZABLE);
|
||||
window.SetTargetFPS(60);
|
||||
|
||||
std::vector<std::shared_ptr<Entity>> entities;
|
||||
entities.reserve(20);
|
||||
|
||||
GameContext context;
|
||||
|
||||
entities.push_back(CreateWorld());
|
||||
entities.push_back(CreateGravityWell());
|
||||
entities.push_back(CreateProbe());
|
||||
entities.push_back(CreateStar(900.0f, 120.0f));
|
||||
entities.push_back(CreateAsteroid(1100.0f, 330.0f));
|
||||
entities.push_back(CreateNullZone(1280.0f, 70.0f));
|
||||
entities.push_back(CreateHUD());
|
||||
SceneManager sceneManager;
|
||||
sceneManager.ChangeScene<StartMenuScene>();
|
||||
|
||||
while (!window.ShouldClose()) {
|
||||
float dt = window.GetFrameTime();
|
||||
|
||||
UpdateAllSystems(entities, context, dt);
|
||||
|
||||
auto worldScroll = entities[0]->GetComponent<ScrollComponent>();
|
||||
auto probeTransform = entities[2]->GetComponent<TransformComponent>();
|
||||
auto hudMeter = entities.back()->GetComponent<MeterComponent>();
|
||||
sceneManager.Update(dt);
|
||||
|
||||
window.BeginDrawing();
|
||||
window.ClearBackground(raylib::Color(11, 15, 26, 255));
|
||||
|
||||
DrawSceneOutline();
|
||||
|
||||
raylib::DrawText("Gravity Surfing", 14, 12, 20, raylib::Color::RayWhite());
|
||||
|
||||
if (worldScroll) {
|
||||
// debug readout for early loop validation
|
||||
raylib::DrawText(TextFormat("scrollX: %.2f", worldScroll->get().scrollX), 14, 40, 16,
|
||||
raylib::Color(125, 225, 205, 255));
|
||||
}
|
||||
|
||||
if (probeTransform) {
|
||||
const auto &probe = probeTransform->get();
|
||||
raylib::DrawText(TextFormat("probe: (%.1f, %.1f)", probe.x, probe.y), 14, 60, 16,
|
||||
raylib::Color(235, 215, 125, 255));
|
||||
}
|
||||
|
||||
if (hudMeter) {
|
||||
raylib::DrawText(TextFormat("meter: %.1f", hudMeter->get().value), 14, 80, 16,
|
||||
raylib::Color(120, 210, 190, 255));
|
||||
}
|
||||
|
||||
for (auto &entity : entities) {
|
||||
if (!entity) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto collectible = entity->GetComponent<CollectibleComponent>();
|
||||
if (collectible && collectible->get().collected) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto render = entity->GetComponent<RenderComponent>();
|
||||
if (render) {
|
||||
render->get().Draw();
|
||||
}
|
||||
}
|
||||
sceneManager.Draw();
|
||||
|
||||
window.EndDrawing();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue