From b4deadd9f4e399207e2530ea39a447c0d9d260a3 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Sat, 2 Dec 2017 19:10:06 +0100 Subject: [PATCH] slightly better physics --- src/creature/Situation.hpp | 2 + src/creature/creature.cpp | 51 ++++++++++++++++++++----- src/ui/CreaturePanel.hpp | 2 + src/ui/ui.cpp | 38 ++++++++++++++++++ src/world/CreatureCreatureCollision.hpp | 2 + src/world/world.cpp | 11 +++++- 6 files changed, 96 insertions(+), 10 deletions(-) diff --git a/src/creature/Situation.hpp b/src/creature/Situation.hpp index 4205cff..3c4a28a 100644 --- a/src/creature/Situation.hpp +++ b/src/creature/Situation.hpp @@ -66,6 +66,8 @@ public: const glm::dvec3 &Velocity() const noexcept { return state.vel; } bool Moving() const noexcept { return glm::length2(state.vel) > 0.0000001; } void Move(const glm::dvec3 &dp) noexcept; + void Accelerate(const glm::dvec3 &dv) noexcept; + void EnforceConstraints(State &) noexcept; void Heading(const glm::dvec3 &h) noexcept { state.dir = h; } const glm::dvec3 &Heading() const noexcept { return state.dir; } diff --git a/src/creature/creature.cpp b/src/creature/creature.cpp index dc857ce..b95b531 100644 --- a/src/creature/creature.cpp +++ b/src/creature/creature.cpp @@ -278,10 +278,11 @@ void Creature::TickState(double dt) { ); state.pos += f.vel * dt; state.vel += f.acc * dt; + situation.EnforceConstraints(state); if (length2(state.vel) > 0.000001) { glm::dvec3 nvel(normalize(state.vel)); double ang = angle(nvel, state.dir); - double turn_rate = PI * 0.5 * dt; + double turn_rate = PI * 0.75 * dt; if (ang < turn_rate) { state.dir = normalize(state.vel); } else if (std::abs(ang - PI) < 0.001) { @@ -291,16 +292,33 @@ void Creature::TickState(double dt) { } } situation.SetState(state); - stats.Exhaustion().Add(length(f.acc) * Mass() / Stamina() * dt); + stats.Exhaustion().Add(length(f.acc) * Mass() / Stamina() * 0.5 * dt); } Situation::Derivative Creature::Step(const Situation::Derivative &ds, double dt) const noexcept { Situation::State s = situation.GetState(); s.pos += ds.vel * dt; s.vel += ds.acc * dt; + glm::dvec3 force(steering.Force(s)); + // gravity = antinormal * mass * Gm / r² + double elevation = s.pos[(situation.Surface() + 2) % 3]; + glm::dvec3 normal(world::Planet::SurfaceNormal(situation.Surface())); + force += glm::dvec3( + -normal + * Mass() * situation.GetPlanet().GravitationalParameter() + / (elevation * elevation)); + // if net force is applied and in contact with surface + if (!allzero(force) && std::abs(std::abs(elevation) - situation.GetPlanet().Radius()) < 0.001) { + // apply friction = -|normal force| * tangential force * coefficient + glm::dvec3 fn(normal * dot(force, normal)); + glm::dvec3 ft(force - fn); + double u = 0.4; + glm::dvec3 friction(-length(fn) * ft * u); + force += friction; + } return { s.vel, - steering.Force(s) / Mass() + force / Mass() }; } @@ -576,7 +594,7 @@ void Split(Creature &c) { // TODO: duplicate situation somehow a->GetSituation().SetPlanetSurface( s.GetPlanet(), s.Surface(), - s.Position() + glm::dvec3(0.0, a->Size() + 0.1, 0.0)); + s.Position() + glm::dvec3(0.0, 0.55 * a->Size(), 0.0)); a->BuildVAO(); std::cout << "[" << int(c.GetSimulation().Time()) << "s] " << a->Name() << " was born" << std::endl; @@ -590,7 +608,7 @@ void Split(Creature &c) { s.GetPlanet().AddCreature(b); b->GetSituation().SetPlanetSurface( s.GetPlanet(), s.Surface(), - s.Position() + glm::dvec3(0.0, b->Size() - 0.1, 0.0)); + s.Position() - glm::dvec3(0.0, 0.55 * b->Size(), 0.0)); b->BuildVAO(); std::cout << "[" << int(c.GetSimulation().Time()) << "s] " << b->Name() << " was born" << std::endl; @@ -700,12 +718,26 @@ const world::TileType &Situation::GetTileType() const noexcept { void Situation::Move(const glm::dvec3 &dp) noexcept { state.pos += dp; + EnforceConstraints(state); +} + +void Situation::Accelerate(const glm::dvec3 &dv) noexcept { + state.vel += dv; + EnforceConstraints(state); +} + +void Situation::EnforceConstraints(State &s) noexcept { if (OnSurface()) { - // enforce ground constraint if (Surface() < 3) { - state.pos[(Surface() + 2) % 3] = std::max(0.0, state.pos[(Surface() + 2) % 3]); + if (s.pos[(Surface() + 2) % 3] < GetPlanet().Radius()) { + s.pos[(Surface() + 2) % 3] = GetPlanet().Radius(); + s.vel[(Surface() + 2) % 3] = std::max(0.0, s.vel[(Surface() + 2) % 3]); + } } else { - state.pos[(Surface() + 2) % 3] = std::min(0.0, state.pos[(Surface() + 2) % 3]); + if (s.pos[(Surface() + 2) % 3] > -GetPlanet().Radius()) { + s.pos[(Surface() + 2) % 3] = -GetPlanet().Radius(); + s.vel[(Surface() + 2) % 3] = std::min(0.0, s.vel[(Surface() + 2) % 3]); + } } } } @@ -715,6 +747,7 @@ void Situation::SetPlanetSurface(world::Planet &p, int srf, const glm::dvec3 &po planet = &p; surface = srf; state.pos = pos; + EnforceConstraints(state); } @@ -746,7 +779,7 @@ void Steering::DontSeparate() noexcept { } void Steering::ResumeSeparate() noexcept { - separating = false; + separating = true; } void Steering::Halt() noexcept { diff --git a/src/ui/CreaturePanel.hpp b/src/ui/CreaturePanel.hpp index 864fede..967e039 100644 --- a/src/ui/CreaturePanel.hpp +++ b/src/ui/CreaturePanel.hpp @@ -52,6 +52,8 @@ private: Label *age; Label *mass; Label *pos; + Label *vel; + Label *dir; Label *tile; Label *goal; Meter *stats[7]; diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index 91ae106..becfb98 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -24,6 +24,8 @@ CreaturePanel::CreaturePanel(const app::Assets &assets) , age(new Label(assets.fonts.medium)) , mass(new Label(assets.fonts.medium)) , pos(new Label(assets.fonts.medium)) +, vel(new Label(assets.fonts.medium)) +, dir(new Label(assets.fonts.medium)) , tile(new Label(assets.fonts.medium)) , goal(new Label(assets.fonts.medium)) , stats{nullptr} @@ -69,6 +71,26 @@ CreaturePanel::CreaturePanel(const app::Assets &assets) ->Spacing(10.0f) ->Direction(Panel::HORIZONTAL); + vel->Text("<00.0, 00.0, 00.0>"); + Label *vel_label = new Label(assets.fonts.medium); + vel_label->Text("Vel"); + Panel *vel_panel = new Panel; + vel_panel + ->Add(vel_label) + ->Add(vel) + ->Spacing(10.0f) + ->Direction(Panel::HORIZONTAL); + + dir->Text("<0.00, 0.00, 0.00>"); + Label *dir_label = new Label(assets.fonts.medium); + dir_label->Text("Dir"); + Panel *dir_panel = new Panel; + dir_panel + ->Add(dir_label) + ->Add(dir) + ->Spacing(10.0f) + ->Direction(Panel::HORIZONTAL); + tile->Text("<00, 00> (mountains)"); Label *tile_label = new Label(assets.fonts.medium); tile_label->Text("Tile"); @@ -165,6 +187,8 @@ CreaturePanel::CreaturePanel(const app::Assets &assets) ->Add(born_panel) ->Add(mass_panel) ->Add(pos_panel) + ->Add(vel_panel) + ->Add(dir_panel) ->Add(tile_panel) ->Add(goal_panel) ->Add(stat_panel) @@ -201,6 +225,20 @@ void CreaturePanel::Draw(app::Assets &assets, graphics::Viewport &viewport) noex << "<" << p.x << ", " << p.y << ", " << p.z << ">"; pos->Text(ss.str()); } + { + const glm::dvec3 &v = c->GetSituation().Velocity(); + std::stringstream ss; + ss << std::fixed << std::setprecision(1) + << "<" << v.x << ", " << v.y << ", " << v.z << ">"; + vel->Text(ss.str()); + } + { + const glm::dvec3 &d = c->GetSituation().GetState().dir; + std::stringstream ss; + ss << std::fixed << std::setprecision(2) + << "<" << d.x << ", " << d.y << ", " << d.z << ">"; + dir->Text(ss.str()); + } { glm::ivec2 t = c->GetSituation().SurfacePosition(); std::stringstream ss; diff --git a/src/world/CreatureCreatureCollision.hpp b/src/world/CreatureCreatureCollision.hpp index 1a903ec..a26b050 100644 --- a/src/world/CreatureCreatureCollision.hpp +++ b/src/world/CreatureCreatureCollision.hpp @@ -30,10 +30,12 @@ public: creature::Creature &A() noexcept { return *a; } const creature::Creature &A() const noexcept { return *a; } const glm::dvec3 &APos() const noexcept; + const glm::dvec3 &AVel() const noexcept; creature::Creature &B() noexcept { return *b; } const creature::Creature &B() const noexcept { return *b; } const glm::dvec3 &BPos() const noexcept; + const glm::dvec3 &BVel() const noexcept; const glm::dvec3 &Normal() const noexcept { return normal; } double Depth() const noexcept { return depth; } diff --git a/src/world/world.cpp b/src/world/world.cpp index 9cd1e02..d7e293a 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -208,7 +208,8 @@ void Body::CheckCollision() noexcept { for (auto &c : collisions) { c.A().GetSituation().Move(c.Normal() * (c.Depth() * -0.5)); c.B().GetSituation().Move(c.Normal() * (c.Depth() * 0.5)); - // TODO: adjust velocities as well + c.A().GetSituation().Accelerate(c.Normal() * -dot(c.Normal(), c.AVel())); + c.B().GetSituation().Accelerate(c.Normal() * -dot(c.Normal(), c.BVel())); // TODO: notify participants so they can be annoyed } } @@ -232,10 +233,18 @@ const glm::dvec3 &CreatureCreatureCollision::APos() const noexcept { return a->GetSituation().Position(); } +const glm::dvec3 &CreatureCreatureCollision::AVel() const noexcept { + return a->GetSituation().Velocity(); +} + const glm::dvec3 &CreatureCreatureCollision::BPos() const noexcept { return b->GetSituation().Position(); } +const glm::dvec3 &CreatureCreatureCollision::BVel() const noexcept { + return b->GetSituation().Velocity(); +} + Orbit::Orbit() : sma(1.0) -- 2.39.2