Improve documentation coverage

master
John Montagu, the 4th Earl of Sandvich 2026-03-16 14:01:33 -07:00
parent bf729d4796
commit 2c43dee225
Signed by: sandvich
GPG Key ID: 9A39BE37E602B22D
15 changed files with 33 additions and 4 deletions

View File

@ -6,6 +6,7 @@
#include "raylib-cpp.hpp"
#include <algorithm>
// main controllable probe with meter, trail, and projection helpers
std::shared_ptr<Entity> CreateProbe() {
auto e = std::make_shared<Entity>();
auto &transform = e->AddComponent<TransformComponent>();
@ -48,6 +49,7 @@ std::shared_ptr<Entity> CreateProbe() {
return e;
}
// helper controller entity for free cursor-based well placement
std::shared_ptr<Entity> CreateGravityWell() {
auto e = std::make_shared<Entity>();
auto &transform = e->AddComponent<TransformComponent>();
@ -60,6 +62,7 @@ std::shared_ptr<Entity> CreateGravityWell() {
return e;
}
// permanent hazard black hole that serves as a heavy obstacle
std::shared_ptr<Entity> CreateBlackHole(float x, float y) {
auto e = std::make_shared<Entity>();
auto &transform = e->AddComponent<TransformComponent>();
@ -70,6 +73,7 @@ std::shared_ptr<Entity> CreateBlackHole(float x, float y) {
scrollable.worldX = x;
auto &well = e->AddComponent<GravityWellComponent>();
// oversized static hazard that always pulls with high mass so the probe has to dodge it
well.mass = static_cast<float>(1 << 21);
well.minDist = 24.0f;
well.controlledByMouse = false;
@ -100,6 +104,7 @@ std::shared_ptr<Entity> CreateBlackHole(float x, float y) {
return e;
}
// player-placed well that expires after ttl and can be cleared via right click
std::shared_ptr<Entity> CreatePlayerBlackHole(float worldX, float y, float scrollX, float ttl) {
auto e = std::make_shared<Entity>();
auto &transform = e->AddComponent<TransformComponent>();
@ -110,6 +115,7 @@ std::shared_ptr<Entity> CreatePlayerBlackHole(float worldX, float y, float scrol
scrollable.worldX = worldX;
auto &well = e->AddComponent<GravityWellComponent>();
// temporary player-placed well that drains meter and lasts exactly ttl seconds
well.mass = static_cast<float>(1 << 22);
well.minDist = 28.0f;
well.controlledByMouse = false;
@ -147,6 +153,7 @@ std::shared_ptr<Entity> CreatePlayerBlackHole(float worldX, float y, float scrol
return e;
}
// collectible star that restores meter and counts toward score
std::shared_ptr<Entity> CreateStar(float x, float y) {
auto e = std::make_shared<Entity>();
auto &t = e->AddComponent<TransformComponent>();
@ -174,6 +181,7 @@ std::shared_ptr<Entity> CreateStar(float x, float y) {
return e;
}
// small hazard that nudges the player when hit
std::shared_ptr<Entity> CreateAsteroid(float x, float y) {
auto e = std::make_shared<Entity>();
auto &t = e->AddComponent<TransformComponent>();
@ -198,6 +206,7 @@ std::shared_ptr<Entity> CreateAsteroid(float x, float y) {
return e;
}
// visual debris after collecting stars to reinforce feedback
std::shared_ptr<Entity> CreateDebris(float x, float y, float vx, float vy, float ttl) {
auto e = std::make_shared<Entity>();
auto &t = e->AddComponent<TransformComponent>();
@ -225,6 +234,7 @@ std::shared_ptr<Entity> CreateDebris(float x, float y, float vx, float vy, float
return e;
}
// null zone that strips gravity and forces the player to avoid it
std::shared_ptr<Entity> CreateNullZone(float x, float width) {
auto e = std::make_shared<Entity>();
auto &t = e->AddComponent<TransformComponent>();
@ -251,6 +261,7 @@ std::shared_ptr<Entity> CreateNullZone(float x, float width) {
return e;
}
// world entity that owns scrolling and spawn logic
std::shared_ptr<Entity> CreateWorld() {
auto e = std::make_shared<Entity>();
e->AddComponent<ScrollComponent>();
@ -258,6 +269,7 @@ std::shared_ptr<Entity> CreateWorld() {
return e;
}
// hud/stat tracker that shows meter and plays sounds
std::shared_ptr<Entity> CreateStats() {
auto e = std::make_shared<Entity>();
e->AddComponent<StatsComponent>();

View File

@ -19,6 +19,7 @@ void CollectibleComponent::Setup() {
return;
}
// probe knock collecting stars is how meter value climbs and provides audiovisual feedback
context->EmitCollectiblePicked(*entity);
entity->QueueFree();

View File

@ -40,6 +40,7 @@ void ColliderComponent::Update(float) {
const float dy = selfTransform->get().y - otherTransform->get().y;
const float r = radius + otherCollider->get().radius;
if ((dx * dx + dy * dy) <= (r * r)) {
// collision emitted per frame keeps gameplay reactive without physics bodies
EmitCollision(*other);
}
}

View File

@ -44,6 +44,7 @@ void GravityReceiverComponent::Update(float dt) {
}
}
if (inVoid) {
// inside a null zone, the probe floats freely until it exits
return;
}

View File

@ -21,7 +21,7 @@ void GravityWellComponent::Update(float) {
return;
}
// Right click removes all player-created black holes
// right click removes all player-created black holes so the player can clear the screen quickly
if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) {
for (auto &ent : *context->entities) {
if (!ent || ent->queuedForFree) {
@ -36,6 +36,7 @@ void GravityWellComponent::Update(float) {
// Do not early return; allow left-click placement to still happen in the same frame
}
// only spawn a new black hole when the player has enough meter and pressed left
if (!IsMouseButtonPressed(MOUSE_BUTTON_LEFT) || !context->statsEntity) {
return;
}

View File

@ -16,6 +16,7 @@ void HazardComponent::Setup() {
return;
}
// hazards instantly end the run by calling the death callback
if (context->onPlayerDeath) {
context->onPlayerDeath();
}

View File

@ -7,6 +7,7 @@ void LifetimeComponent::Setup() {}
void LifetimeComponent::Update(float dt) {
remaining -= dt;
if (remaining <= 0.0f) {
// helper component that simply removes itself when the ttl expires
entity->QueueFree();
}
}

View File

@ -67,6 +67,7 @@ bool PhysicsComponent::IsInsideNullZone(double xPos) const {
return false;
}
// looks weird because of formatter
bool PhysicsComponent::ComputeGravityDeltaVelocity(double px, double py, double dt, double &dvx,
double &dvy, bool ignoreWellActive) const {
dvx = 0.0;
@ -80,11 +81,13 @@ bool PhysicsComponent::ComputeGravityDeltaVelocity(double px, double py, double
if (context && entity == context->probeEntity && context->statsEntity) {
auto stats = context->statsEntity->GetComponent<StatsComponent>();
if (stats && stats->get().value <= 0.0f) {
// meter drained, block gravity from anything that isn't always active
probeMeterDepleted = true;
}
}
if (IsInsideNullZone(px)) {
// null zone overrides gravity, so the probe/globally simulated object stops feeling wells
return false;
}
@ -115,6 +118,7 @@ bool PhysicsComponent::ComputeGravityDeltaVelocity(double px, double py, double
continue;
}
// guard against infinite force by respecting the well's minimum distance
const double clampedDist = std::max(dist, static_cast<double>(wellGravity->get().minDist));
const double force =
static_cast<double>(wellGravity->get().mass) / (clampedDist * clampedDist);

View File

@ -22,6 +22,7 @@ void ProbeStateComponent::Update(float) {
transform->get().x < -20.0f ||
transform->get().x > static_cast<float>(GetScreenWidth() + 20)) {
if (context->onPlayerDeath) {
// leaving the viewport is treated as death to keep the probe bounded
context->onPlayerDeath();
}
}

View File

@ -56,6 +56,8 @@ void ProjectionComponent::Update(float) {
auto wellGravity = other->GetComponent<GravityWellComponent>();
if (wellGravity && wellGravity->get().active) {
// highlight arc when another well is active so the player knows the projection is
// influenced
highlightActive = true;
break;
}
@ -84,6 +86,8 @@ void ProjectionComponent::Update(float) {
}
}
// storing each simulated position gives the hud the full trajectory so the player can line
// up placements
points.push_back({static_cast<float>(px), static_cast<float>(py)});
}

View File

@ -6,6 +6,7 @@ void ScrollComponent::Update(float dt) {
speed += accel * dt;
scrollX += speed * dt * 60.0f;
if (context) {
// stores our current scroll speed for components that rely on the camera position
context->scrollX = scrollX;
}
}

View File

@ -15,6 +15,7 @@ void ScrollableComponent::Update(float) {
return;
}
// keeps the drawable aligned with the camera by subtracting the global scroll offset
transform->get().x = worldX - context->scrollX;
}

View File

@ -31,6 +31,7 @@ void SpawnComponent::Update(float) {
const float cameraX = scroll->get().scrollX;
const float spawnLimit = cameraX + spawnAheadDistance;
// 70% stars, 20% asteroids, 5% null zones, 5% hazards -> keeps early play mostly collectible
while (cursorWX < spawnLimit) {
const float r = static_cast<float>(GetRandomValue(0, 99));
if (r < 70.0f) {

View File

@ -6,6 +6,7 @@ void StatsComponent::SetValue(float newValue) {
const float oldValue = value;
value = newValue;
if (context && oldValue != value) {
// notify listeners so the hud and gravity meter stay in sync with the updated value
context->EmitMeterChanged(oldValue, value);
}
}

View File

@ -14,9 +14,7 @@ void GameplayScene::Enter() {
meterValue = 60.0f;
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.
// queue the death scene with the current star count so the recap is accurate
manager.QueueSceneChange<DeathScene>(collectedCount, this->isMuted);
};
context.AddCollectiblePickedListener([this](Entity &collectible) {