From b0e73e632f0b681a0af78f889dd82d370563944a Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Mon, 27 Nov 2017 22:05:20 +0100 Subject: [PATCH] use RK4 to integrate creature state --- src/creature/Creature.hpp | 9 +++---- src/creature/Situation.hpp | 26 +++++++++++++++++-- src/creature/Steering.hpp | 5 ++-- src/creature/creature.cpp | 52 +++++++++++++++++++++++++------------- src/creature/goal.cpp | 2 +- 5 files changed, 64 insertions(+), 30 deletions(-) diff --git a/src/creature/Creature.hpp b/src/creature/Creature.hpp index 7c06cc8..e2f9b44 100644 --- a/src/creature/Creature.hpp +++ b/src/creature/Creature.hpp @@ -94,15 +94,14 @@ public: Steering &GetSteering() noexcept { return steering; } const Steering &GetSteering() const noexcept { return steering; } - void Velocity(const glm::dvec3 &v) noexcept { vel = v; } - const glm::dvec3 &Velocity() const noexcept { return vel; } - bool Moving() const noexcept { return glm::length2(vel) < 0.00000001; } - glm::dmat4 LocalTransform() noexcept; void BuildVAO(); void Draw(graphics::Viewport &); +private: + Situation::Derivative Step(const Situation::Derivative &ds, double dt) const noexcept; + private: world::Simulation ∼ std::string name; @@ -127,8 +126,6 @@ private: Situation situation; Steering steering; - glm::dvec3 vel; - struct Attributes { glm::vec3 position; glm::vec3 normal; diff --git a/src/creature/Situation.hpp b/src/creature/Situation.hpp index a60aeb7..a12f422 100644 --- a/src/creature/Situation.hpp +++ b/src/creature/Situation.hpp @@ -14,6 +14,24 @@ namespace creature { class Situation { +public: + struct State { + glm::dvec3 pos; + glm::dvec3 vel; + State( + const glm::dvec3 &pos = glm::dvec3(0.0), + const glm::dvec3 &vel = glm::dvec3(0.0)) + : pos(pos), vel(vel) { } + }; + struct Derivative { + glm::dvec3 vel; + glm::dvec3 acc; + Derivative( + const glm::dvec3 &vel = glm::dvec3(0.0), + const glm::dvec3 &acc = glm::dvec3(0.0)) + : vel(vel), acc(acc) { } + }; + public: Situation(); ~Situation(); @@ -29,18 +47,22 @@ public: world::Planet &GetPlanet() const noexcept { return *planet; } bool OnSurface() const noexcept; int Surface() const noexcept { return surface; } - const glm::dvec3 &Position() const noexcept { return position; } + const glm::dvec3 &Position() const noexcept { return state.pos; } bool OnTile() const noexcept; glm::ivec2 SurfacePosition() const noexcept; world::Tile &GetTile() const noexcept; const world::TileType &GetTileType() const noexcept; + void SetState(const State &s) noexcept { state = s; } + const State &GetState() const noexcept { return state; } + + bool Moving() const noexcept { return glm::length2(state.vel) < 0.00000001; } void Move(const glm::dvec3 &dp) noexcept; void SetPlanetSurface(world::Planet &, int srf, const glm::dvec3 &pos) noexcept; public: world::Planet *planet; - glm::dvec3 position; + State state; int surface; enum { LOST, diff --git a/src/creature/Steering.hpp b/src/creature/Steering.hpp index 51f2c63..3ccf9e3 100644 --- a/src/creature/Steering.hpp +++ b/src/creature/Steering.hpp @@ -1,14 +1,13 @@ #ifndef BLOBS_CREATURE_STEERING_HPP_ #define BLOBS_CREATURE_STEERING_HPP_ +#include "Situation.hpp" #include "../math/glm.hpp" namespace blobs { namespace creature { -class Creature; - class Steering { public: @@ -26,7 +25,7 @@ public: void Halt() noexcept; void GoTo(const glm::dvec3 &) noexcept; - glm::dvec3 Acceleration(Creature &) const noexcept; + glm::dvec3 Acceleration(const Situation::State &) const noexcept; private: bool SumForce(glm::dvec3 &out, const glm::dvec3 &in) const noexcept; diff --git a/src/creature/creature.cpp b/src/creature/creature.cpp index f51f52c..d870755 100644 --- a/src/creature/creature.cpp +++ b/src/creature/creature.cpp @@ -43,7 +43,6 @@ Creature::Creature(world::Simulation &sim) , goals() , situation() , steering() -, vel(0.0) , vao() { } @@ -106,10 +105,20 @@ bool GoalCompare(const std::unique_ptr &a, const std::unique_ptr &b) } void Creature::Tick(double dt) { - // TODO: better integration method - glm::dvec3 acc(steering.Acceleration(*this)); - situation.Move(vel * dt); - vel += acc * dt; + { + Situation::State state(situation.GetState()); + Situation::Derivative a(Step(Situation::Derivative(), 0.0)); + Situation::Derivative b(Step(a, dt * 0.5)); + Situation::Derivative c(Step(b, dt * 0.5)); + Situation::Derivative d(Step(c, dt)); + Situation::Derivative f( + (1.0 / 6.0) * (a.vel + 2.0 * (b.vel + c.vel) + d.vel), + (1.0 / 6.0) * (a.acc + 2.0 * (b.acc + c.acc) + d.acc) + ); + state.pos += f.vel * dt; + state.vel += f.acc * dt; + situation.SetState(state); + } if (Age() > properties.death_age) { std::cout << "[" << int(sim.Time()) << "s] " @@ -153,6 +162,13 @@ void Creature::Tick(double 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; + return { s.vel, steering.Acceleration(s) }; +} + glm::dmat4 Creature::LocalTransform() noexcept { // TODO: surface transform const double half_size = size * 0.5; @@ -445,7 +461,7 @@ std::string NameGenerator::Sequential() { Situation::Situation() : planet(nullptr) -, position(0.0) +, state(glm::dvec3(0.0), glm::dvec3(0.0)) , surface(0) , type(LOST) { } @@ -462,34 +478,34 @@ bool Situation::OnSurface() const noexcept { } bool Situation::OnTile() const noexcept { - glm::ivec2 t(planet->SurfacePosition(surface, position)); + glm::ivec2 t(planet->SurfacePosition(surface, state.pos)); return type == PLANET_SURFACE && t.x >= 0 && t.x < planet->SideLength() && t.y >= 0 && t.y < planet->SideLength(); } glm::ivec2 Situation::SurfacePosition() const noexcept { - return planet->SurfacePosition(surface, position); + return planet->SurfacePosition(surface, state.pos); } world::Tile &Situation::GetTile() const noexcept { - glm::ivec2 t(planet->SurfacePosition(surface, position)); + glm::ivec2 t(planet->SurfacePosition(surface, state.pos)); return planet->TileAt(surface, t.x, t.y); } const world::TileType &Situation::GetTileType() const noexcept { - glm::ivec2 t(planet->SurfacePosition(surface, position)); + glm::ivec2 t(planet->SurfacePosition(surface, state.pos)); return planet->TypeAt(surface, t.x, t.y); } void Situation::Move(const glm::dvec3 &dp) noexcept { - position += dp; + state.pos += dp; if (OnSurface()) { // enforce ground constraint if (Surface() < 3) { - position[(Surface() + 2) % 3] = std::max(0.0, position[(Surface() + 2) % 3]); + state.pos[(Surface() + 2) % 3] = std::max(0.0, state.pos[(Surface() + 2) % 3]); } else { - position[(Surface() + 2) % 3] = std::min(0.0, position[(Surface() + 2) % 3]); + state.pos[(Surface() + 2) % 3] = std::min(0.0, state.pos[(Surface() + 2) % 3]); } } } @@ -498,7 +514,7 @@ void Situation::SetPlanetSurface(world::Planet &p, int srf, const glm::dvec3 &po type = PLANET_SURFACE; planet = &p; surface = srf; - position = pos; + state.pos = pos; } @@ -524,15 +540,15 @@ void Steering::GoTo(const glm::dvec3 &t) noexcept { seeking = true; } -glm::dvec3 Steering::Acceleration(Creature &c) const noexcept { +glm::dvec3 Steering::Acceleration(const Situation::State &s) const noexcept { glm::dvec3 acc(0.0); if (halting) { - SumForce(acc, c.Velocity() * -max_accel); + SumForce(acc, s.vel * -max_accel); } if (seeking) { - glm::dvec3 diff = seek_target - c.GetSituation().Position(); + glm::dvec3 diff = seek_target - s.pos; if (!allzero(diff)) { - SumForce(acc, ((normalize(diff) * max_speed) - c.Velocity()) * max_accel); + SumForce(acc, ((normalize(diff) * max_speed) - s.vel) * max_accel); } } return acc; diff --git a/src/creature/goal.cpp b/src/creature/goal.cpp index 8f8a3fa..ee51a91 100644 --- a/src/creature/goal.cpp +++ b/src/creature/goal.cpp @@ -138,7 +138,7 @@ void LocateResourceGoal::Action() { } } else if (OnTargetTile()) { GetSteering().Halt(); - if (!GetCreature().Moving()) { + if (!GetSituation().Moving()) { SetComplete(); } } else { -- 2.39.2