From 78c07da39f753660cb96227d85080b6e60268c48 Mon Sep 17 00:00:00 2001 From: HumanoidSandvichDispenser Date: Sun, 15 Mar 2026 19:24:03 -0700 Subject: [PATCH] Add gravity well and physics --- as6/Components.hpp | 54 ++++++++++++++++++++++++++++++++++++++++++++-- as6/Entities.hpp | 36 ++++++++++++++++++++----------- as6/Systems.hpp | 38 +++++++++++++++++++++++++++++++- as6/main.cpp | 31 ++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 15 deletions(-) diff --git a/as6/Components.hpp b/as6/Components.hpp index 51a2638..455a56e 100644 --- a/as6/Components.hpp +++ b/as6/Components.hpp @@ -2,6 +2,8 @@ #include "Entity.hpp" +#include "raylib.h" + #include #include @@ -41,8 +43,23 @@ 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) override {} + void Update(float dt) override { + auto transform = entity->GetComponent(); + if (!transform) { + return; + } + + // TODO: use buffered input + 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 {} }; @@ -50,7 +67,40 @@ struct GravityReceiverComponent : public Component { Entity *well = nullptr; bool inVoid = false; void Setup() override {} - void Update(float) override {} + void Update(float dt) override { + (void)inVoid; + + 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; + } + + if (!wellGravity->get().active) { + 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; + } void Cleanup() override {} }; diff --git a/as6/Entities.hpp b/as6/Entities.hpp index 99f29e3..f2bb02b 100644 --- a/as6/Entities.hpp +++ b/as6/Entities.hpp @@ -10,12 +10,13 @@ std::shared_ptr CreateProbe() { transform.x = 96.0f; transform.y = 230.0f; - auto &physics = e->AddComponent(); - physics.vx = 165.0f; - physics.vy = 0.0f; - physics.speedCap = 420.0f; - e->AddComponent(); + + auto &physics = e->AddComponent(); + physics.vx = 108.0f; + physics.vy = 0.0f; + physics.speedCap = 8192.0f; + e->AddComponent(); e->AddComponent(); e->AddComponent(); @@ -25,8 +26,15 @@ std::shared_ptr CreateProbe() { std::shared_ptr CreateGravityWell() { auto e = std::make_shared(); - e->AddComponent(); - e->AddComponent(); + auto &transform = e->AddComponent(); + transform.x = 96.0f; + transform.y = 230.0f; + + auto &well = e->AddComponent(); + well.mass = (float)(1 << 22); + well.minDist = 28.0f; + well.followLerp = 12.0f; + e->AddComponent(); return e; } @@ -36,7 +44,8 @@ std::shared_ptr CreateStar(float x, float y) { auto &t = e->AddComponent(); t.x = x; t.y = y; - e->AddComponent(); + auto &scrollable = e->AddComponent(); + scrollable.worldX = x; e->AddComponent(); e->AddComponent(); e->AddComponent(); @@ -48,7 +57,8 @@ std::shared_ptr CreateAsteroid(float x, float y) { auto &t = e->AddComponent(); t.x = x; t.y = y; - e->AddComponent(); + auto &scrollable = e->AddComponent(); + scrollable.worldX = x; e->AddComponent(); e->AddComponent(); return e; @@ -58,9 +68,11 @@ std::shared_ptr CreateNullZone(float x, float width) { auto e = std::make_shared(); auto &t = e->AddComponent(); t.x = x; - (void)width; - e->AddComponent(); - e->AddComponent(); + auto &scrollable = e->AddComponent(); + scrollable.worldX = x; + + auto &nullZone = e->AddComponent(); + nullZone.width = width; e->AddComponent(); return e; } diff --git a/as6/Systems.hpp b/as6/Systems.hpp index 84ebd69..68ae783 100644 --- a/as6/Systems.hpp +++ b/as6/Systems.hpp @@ -1,14 +1,50 @@ #pragma once +#include "Components.hpp" #include "Entity.hpp" #include #include void UpdateAllSystems(std::vector> &entities, float deltaTime) { + std::shared_ptr worldEntity; + std::shared_ptr wellEntity; + float scrollX = 0.0f; + + if (!entities.empty()) { + worldEntity = entities[0]; + } + if (entities.size() > 1) { + wellEntity = entities[1]; + } + + if (worldEntity) { + worldEntity->Update(deltaTime); + auto scroll = worldEntity->GetComponent(); + if (scroll) { + scrollX = scroll->get().scrollX; + } + } + + if (wellEntity) { + wellEntity->Update(deltaTime); + } + for (auto &entity : entities) { - if (!entity) { + if (entity == worldEntity || entity == wellEntity || !entity) { continue; } + + auto receiver = entity->GetComponent(); + if (receiver) { + receiver->get().well = wellEntity.get(); + } + + auto transform = entity->GetComponent(); + auto scrollable = entity->GetComponent(); + if (transform && scrollable) { + transform->get().x = scrollable->get().worldX - scrollX; + } + entity->Update(deltaTime); } } diff --git a/as6/main.cpp b/as6/main.cpp index fd68140..649a7d5 100644 --- a/as6/main.cpp +++ b/as6/main.cpp @@ -17,6 +17,9 @@ int main() { 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()); while (!window.ShouldClose()) { @@ -25,7 +28,12 @@ int main() { UpdateAllSystems(entities, dt); auto worldScroll = entities[0]->GetComponent(); + auto wellTransform = entities[1]->GetComponent(); auto probeTransform = entities[2]->GetComponent(); + auto starTransform = entities[3]->GetComponent(); + auto asteroidTransform = entities[4]->GetComponent(); + auto nullTransform = entities[5]->GetComponent(); + auto nullZone = entities[5]->GetComponent(); window.BeginDrawing(); window.ClearBackground(raylib::Color(11, 15, 26, 255)); @@ -47,6 +55,29 @@ int main() { raylib::Color(235, 215, 125, 255)); } + if (wellTransform) { + const auto &well = wellTransform->get(); + ::DrawCircleLines(static_cast(well.x), static_cast(well.y), 18.0f, + raylib::Color(86, 197, 255, 255)); + } + + if (starTransform) { + const auto &star = starTransform->get(); + ::DrawCircleV({star.x, star.y}, 6.0f, raylib::Color(255, 223, 86, 255)); + } + + if (asteroidTransform) { + const auto &asteroid = asteroidTransform->get(); + ::DrawCircleV({asteroid.x, asteroid.y}, 13.0f, raylib::Color(116, 126, 142, 255)); + } + + if (nullTransform && nullZone) { + const auto &zone = nullTransform->get(); + const int width = static_cast(nullZone->get().width); + ::DrawRectangle(static_cast(zone.x), 0, width, GetScreenHeight(), + raylib::Color(96, 64, 146, 80)); + } + window.EndDrawing(); }