#pragma once #include "Entity.hpp" #include "GameContext.hpp" #include "raylib.h" #include #include #include #include struct TransformComponent : public Component { float x = 0.0f; float y = 0.0f; void Setup() override {} void Update(float) override {} void Cleanup() override {} }; struct PhysicsComponent : public Component { float vx = 0.0f; float vy = 0.0f; float speedCap = 400.0f; void Setup() override {} void Update(float dt) override { auto transform = entity->GetComponent(); if (!transform) { return; } const float speed = std::sqrt(vx * vx + vy * vy); if (speed > speedCap && speed > 0.0f) { const float scale = speedCap / speed; vx *= scale; vy *= scale; } transform->get().x += vx * dt; transform->get().y += vy * dt; } void Cleanup() override {} }; struct GravityWellComponent : public Component { float mass = 150000.0f; float minDist = 30.0f; bool active = false; float followLerp = 12.0f; void Setup() override {} void Update(float dt) override { auto transform = entity->GetComponent(); if (!transform) { return; } active = IsMouseButtonDown(MOUSE_BUTTON_LEFT); const Vector2 mouse = GetMousePosition(); auto &t = transform->get(); const float blend = std::clamp(followLerp * dt, 0.0f, 1.0f); t.x += (mouse.x - t.x) * blend; t.y += (mouse.y - t.y) * blend; } void Cleanup() override {} }; struct ScrollComponent : public Component { float scrollX = 0.0f; float speed = 2.0f; float accel = 0.018f; void Setup() override {} void Update(float dt) override { speed += accel * dt; scrollX += speed * dt * 60.0f; if (context) { context->scrollX = scrollX; } } void Cleanup() override {} }; struct MeterComponent : public Component { float value = 60.0f; float maxValue = 100.0f; 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 {} }; struct NullZoneComponent : public Component { float width = 70.0f; void Setup() override {} void Update(float) override {} void Cleanup() override {} }; struct ColliderComponent : public Component { float radius = 8.0f; std::vector> onCollision; void Setup() override {} void EmitCollision(Entity &other) { for (auto &callback : onCollision) { callback(other); } } void AddCollisionListener(std::function callback) { onCollision.push_back(std::move(callback)); } void Update(float) override {} void Cleanup() override {} }; struct ScrollableComponent : public Component { float worldX = 0.0f; void Setup() override {} void Update(float) override { if (!context) { return; } auto transform = entity->GetComponent(); if (!transform) { return; } transform->get().x = worldX - context->scrollX; } void Cleanup() override {} }; struct SpawnComponent : public Component { float cursorWX = 0.0f; void Setup() override {} void Update(float) override {} void Cleanup() override {} }; struct TrailComponent : public Component { void Setup() override {} void Update(float) override {} void Cleanup() override {} }; struct ProjectionComponent : public Component { void Setup() override {} void Update(float) override {} void Cleanup() override {} }; struct CollectibleComponent : public Component { bool collected = false; void Setup() override { auto selfCollider = entity->GetComponent(); if (!selfCollider) { return; } selfCollider->get().AddCollisionListener([this](Entity &other) { if (collected || !context || !context->probeEntity || &other != context->probeEntity) { return; } collected = true; context->EmitCollectiblePicked(*entity); if (!context->hudEntity) { return; } auto meter = context->hudEntity->GetComponent(); if (!meter) { return; } meter->get().AddValue(meter->get().gainPerStar); }); } void Update(float) override {} void Cleanup() override {} }; struct HazardComponent : public Component { void Setup() override { auto selfCollider = entity->GetComponent(); if (!selfCollider) { return; } 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 {} }; struct GravityReceiverComponent : public Component { Entity *well = nullptr; bool inVoid = false; void Setup() override {} void Update(float dt) override { if (!context || !context->probeEntity || entity != context->probeEntity) { return; } if (!well && context->wellEntity) { well = context->wellEntity; } if (!well) { return; } auto myTransform = entity->GetComponent(); auto physics = entity->GetComponent(); auto wellTransform = well->GetComponent(); auto wellGravity = well->GetComponent(); if (!myTransform || !physics || !wellTransform || !wellGravity) { return; } MeterComponent *meterPtr = nullptr; if (context->hudEntity) { auto meter = context->hudEntity->GetComponent(); if (meter) { meterPtr = &meter->get(); } } if (!wellGravity->get().active) { return; } if (meterPtr && meterPtr->value <= 0.0f) { return; } inVoid = false; if (context->entities) { for (auto &other : *context->entities) { if (!other || other.get() == entity) { continue; } auto zone = other->GetComponent(); auto zoneTransform = other->GetComponent(); if (!zone || !zoneTransform) { continue; } const float left = zoneTransform->get().x; const float right = left + zone->get().width; if (myTransform->get().x >= left && myTransform->get().x <= right) { inVoid = true; break; } } } if (inVoid) { return; } const float dx = wellTransform->get().x - myTransform->get().x; const float dy = wellTransform->get().y - myTransform->get().y; const float dist = std::sqrt(dx * dx + dy * dy); if (dist <= 0.0001f) { return; } 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; if (meterPtr) { meterPtr->Drain(meterPtr->drainRate * dt); } } void Cleanup() override {} }; struct ProbeStateComponent : public Component { float spawnX = 96.0f; 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) { return; } auto transform = entity->GetComponent(); if (!transform) { return; } if (transform->get().y < -20.0f || transform->get().y > static_cast(GetScreenHeight() + 20) || transform->get().x < -20.0f) { if (context->onPlayerDeath) { context->onPlayerDeath(); } } } void Cleanup() override {} }; struct HudComponent : public Component { void Setup() override {} void Update(float) override {} void Cleanup() override {} }; struct RenderComponent : public Component { std::function draw; virtual void Draw() { if (draw) { draw(); } } void Setup() override {} void Update(float) override {} void Cleanup() override {} };