Add gravity well and physics

master
John Montagu, the 4th Earl of Sandvich 2026-03-15 19:24:03 -07:00
parent 5abb201ed3
commit 78c07da39f
Signed by: sandvich
GPG Key ID: 9A39BE37E602B22D
4 changed files with 144 additions and 15 deletions

View File

@ -2,6 +2,8 @@
#include "Entity.hpp" #include "Entity.hpp"
#include "raylib.h"
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
@ -41,8 +43,23 @@ struct GravityWellComponent : public Component {
float mass = 150000.0f; float mass = 150000.0f;
float minDist = 30.0f; float minDist = 30.0f;
bool active = false; bool active = false;
float followLerp = 12.0f;
void Setup() override {} void Setup() override {}
void Update(float) override {} void Update(float dt) override {
auto transform = entity->GetComponent<TransformComponent>();
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 {} void Cleanup() override {}
}; };
@ -50,7 +67,40 @@ struct GravityReceiverComponent : public Component {
Entity *well = nullptr; Entity *well = nullptr;
bool inVoid = false; bool inVoid = false;
void Setup() override {} void Setup() override {}
void Update(float) override {} void Update(float dt) override {
(void)inVoid;
if (!well) {
return;
}
auto myTransform = entity->GetComponent<TransformComponent>();
auto physics = entity->GetComponent<PhysicsComponent>();
auto wellTransform = well->GetComponent<TransformComponent>();
auto wellGravity = well->GetComponent<GravityWellComponent>();
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 {} void Cleanup() override {}
}; };

View File

@ -10,12 +10,13 @@ std::shared_ptr<Entity> CreateProbe() {
transform.x = 96.0f; transform.x = 96.0f;
transform.y = 230.0f; transform.y = 230.0f;
auto &physics = e->AddComponent<PhysicsComponent>();
physics.vx = 165.0f;
physics.vy = 0.0f;
physics.speedCap = 420.0f;
e->AddComponent<GravityReceiverComponent>(); e->AddComponent<GravityReceiverComponent>();
auto &physics = e->AddComponent<PhysicsComponent>();
physics.vx = 108.0f;
physics.vy = 0.0f;
physics.speedCap = 8192.0f;
e->AddComponent<ColliderComponent>(); e->AddComponent<ColliderComponent>();
e->AddComponent<TrailComponent>(); e->AddComponent<TrailComponent>();
e->AddComponent<ProjectionComponent>(); e->AddComponent<ProjectionComponent>();
@ -25,8 +26,15 @@ std::shared_ptr<Entity> CreateProbe() {
std::shared_ptr<Entity> CreateGravityWell() { std::shared_ptr<Entity> CreateGravityWell() {
auto e = std::make_shared<Entity>(); auto e = std::make_shared<Entity>();
e->AddComponent<TransformComponent>(); auto &transform = e->AddComponent<TransformComponent>();
e->AddComponent<GravityWellComponent>(); transform.x = 96.0f;
transform.y = 230.0f;
auto &well = e->AddComponent<GravityWellComponent>();
well.mass = (float)(1 << 22);
well.minDist = 28.0f;
well.followLerp = 12.0f;
e->AddComponent<RenderComponent>(); e->AddComponent<RenderComponent>();
return e; return e;
} }
@ -36,7 +44,8 @@ std::shared_ptr<Entity> CreateStar(float x, float y) {
auto &t = e->AddComponent<TransformComponent>(); auto &t = e->AddComponent<TransformComponent>();
t.x = x; t.x = x;
t.y = y; t.y = y;
e->AddComponent<ScrollableComponent>(); auto &scrollable = e->AddComponent<ScrollableComponent>();
scrollable.worldX = x;
e->AddComponent<ColliderComponent>(); e->AddComponent<ColliderComponent>();
e->AddComponent<CollectibleComponent>(); e->AddComponent<CollectibleComponent>();
e->AddComponent<RenderComponent>(); e->AddComponent<RenderComponent>();
@ -48,7 +57,8 @@ std::shared_ptr<Entity> CreateAsteroid(float x, float y) {
auto &t = e->AddComponent<TransformComponent>(); auto &t = e->AddComponent<TransformComponent>();
t.x = x; t.x = x;
t.y = y; t.y = y;
e->AddComponent<ScrollableComponent>(); auto &scrollable = e->AddComponent<ScrollableComponent>();
scrollable.worldX = x;
e->AddComponent<ColliderComponent>(); e->AddComponent<ColliderComponent>();
e->AddComponent<RenderComponent>(); e->AddComponent<RenderComponent>();
return e; return e;
@ -58,9 +68,11 @@ std::shared_ptr<Entity> CreateNullZone(float x, float width) {
auto e = std::make_shared<Entity>(); auto e = std::make_shared<Entity>();
auto &t = e->AddComponent<TransformComponent>(); auto &t = e->AddComponent<TransformComponent>();
t.x = x; t.x = x;
(void)width; auto &scrollable = e->AddComponent<ScrollableComponent>();
e->AddComponent<ScrollableComponent>(); scrollable.worldX = x;
e->AddComponent<NullZoneComponent>();
auto &nullZone = e->AddComponent<NullZoneComponent>();
nullZone.width = width;
e->AddComponent<RenderComponent>(); e->AddComponent<RenderComponent>();
return e; return e;
} }

View File

@ -1,14 +1,50 @@
#pragma once #pragma once
#include "Components.hpp"
#include "Entity.hpp" #include "Entity.hpp"
#include <memory> #include <memory>
#include <vector> #include <vector>
void UpdateAllSystems(std::vector<std::shared_ptr<Entity>> &entities, float deltaTime) { void UpdateAllSystems(std::vector<std::shared_ptr<Entity>> &entities, float deltaTime) {
std::shared_ptr<Entity> worldEntity;
std::shared_ptr<Entity> 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<ScrollComponent>();
if (scroll) {
scrollX = scroll->get().scrollX;
}
}
if (wellEntity) {
wellEntity->Update(deltaTime);
}
for (auto &entity : entities) { for (auto &entity : entities) {
if (!entity) { if (entity == worldEntity || entity == wellEntity || !entity) {
continue; continue;
} }
auto receiver = entity->GetComponent<GravityReceiverComponent>();
if (receiver) {
receiver->get().well = wellEntity.get();
}
auto transform = entity->GetComponent<TransformComponent>();
auto scrollable = entity->GetComponent<ScrollableComponent>();
if (transform && scrollable) {
transform->get().x = scrollable->get().worldX - scrollX;
}
entity->Update(deltaTime); entity->Update(deltaTime);
} }
} }

View File

@ -17,6 +17,9 @@ int main() {
entities.push_back(CreateWorld()); entities.push_back(CreateWorld());
entities.push_back(CreateGravityWell()); entities.push_back(CreateGravityWell());
entities.push_back(CreateProbe()); 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()); entities.push_back(CreateHUD());
while (!window.ShouldClose()) { while (!window.ShouldClose()) {
@ -25,7 +28,12 @@ int main() {
UpdateAllSystems(entities, dt); UpdateAllSystems(entities, dt);
auto worldScroll = entities[0]->GetComponent<ScrollComponent>(); auto worldScroll = entities[0]->GetComponent<ScrollComponent>();
auto wellTransform = entities[1]->GetComponent<TransformComponent>();
auto probeTransform = entities[2]->GetComponent<TransformComponent>(); auto probeTransform = entities[2]->GetComponent<TransformComponent>();
auto starTransform = entities[3]->GetComponent<TransformComponent>();
auto asteroidTransform = entities[4]->GetComponent<TransformComponent>();
auto nullTransform = entities[5]->GetComponent<TransformComponent>();
auto nullZone = entities[5]->GetComponent<NullZoneComponent>();
window.BeginDrawing(); window.BeginDrawing();
window.ClearBackground(raylib::Color(11, 15, 26, 255)); window.ClearBackground(raylib::Color(11, 15, 26, 255));
@ -47,6 +55,29 @@ int main() {
raylib::Color(235, 215, 125, 255)); raylib::Color(235, 215, 125, 255));
} }
if (wellTransform) {
const auto &well = wellTransform->get();
::DrawCircleLines(static_cast<int>(well.x), static_cast<int>(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<int>(nullZone->get().width);
::DrawRectangle(static_cast<int>(zone.x), 0, width, GetScreenHeight(),
raylib::Color(96, 64, 146, 80));
}
window.EndDrawing(); window.EndDrawing();
} }