]> git.localhorst.tv Git - blank.git/commitdiff
use "forces" for entity control and RK4 integrator
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 16 Oct 2015 14:33:52 +0000 (16:33 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 16 Oct 2015 14:33:52 +0000 (16:33 +0200)
src/ai/ai.cpp
src/client/NetworkedInput.hpp
src/client/net.cpp
src/ui/ui.cpp
src/world/Entity.hpp
src/world/EntityDerivative.hpp [new file with mode: 0644]
src/world/EntityState.hpp
src/world/world.cpp

index d50aee5b6219aa06f170bc86b3f03eb0fb1cf7e3..7ada5a34b3bc6d80912f0dfd876e8a721217fff6 100644 (file)
@@ -36,7 +36,7 @@ void Chaser::Update(int dt) {
        glm::vec3 diff(Target().AbsoluteDifference(Controlled()));
        float dist = length(diff);
        if (dist < std::numeric_limits<float>::epsilon()) {
-               Controlled().Velocity(glm::vec3(0.0f));
+               Controlled().TargetVelocity(glm::vec3(0.0f));
                return;
        }
        glm::vec3 norm_diff(diff / dist);
@@ -49,13 +49,13 @@ void Chaser::Update(int dt) {
        }
 
        if (!line_of_sight) {
-               Controlled().Velocity(glm::vec3(0.0f));
+               Controlled().TargetVelocity(glm::vec3(0.0f));
        } else if (dist > stop_dist) {
-               Controlled().Velocity(norm_diff * chase_speed);
+               Controlled().TargetVelocity(norm_diff * chase_speed);
        } else if (dist < flee_dist) {
-               Controlled().Velocity(norm_diff * flee_speed);
+               Controlled().TargetVelocity(norm_diff * flee_speed);
        } else {
-               Controlled().Velocity(glm::vec3(0.0f));
+               Controlled().TargetVelocity(glm::vec3(0.0f));
        }
 }
 
@@ -97,10 +97,10 @@ void RandomWalk::Update(int dt) {
                Change();
        } else if (lerp_time > 0) {
                float a = std::min(lerp_time / lerp_max, 1.0f);
-               Controlled().Velocity(mix(target_vel, start_vel, a));
+               Controlled().TargetVelocity(mix(target_vel, start_vel, a));
                Controlled().AngularVelocity(mix(target_rot, start_rot, a));
        } else {
-               Controlled().Velocity(target_vel);
+               Controlled().TargetVelocity(target_vel);
                Controlled().AngularVelocity(target_rot);
        }
 }
index 462b6a721155f0a3c7f672f87c79f0113d2c8555..36382b93225632d1b4056af8d3e9639f6b162d74 100644 (file)
@@ -36,10 +36,11 @@ private:
 
        struct PlayerHistory {
                EntityState state;
+               glm::vec3 tgt_vel;
                int delta_t;
                std::uint16_t packet;
-               PlayerHistory(EntityState s, int dt, std::uint16_t p)
-               : state(s), delta_t(dt), packet(p) { }
+               PlayerHistory(EntityState s, const glm::vec3 &tv, int dt, std::uint16_t p)
+               : state(s), tgt_vel(tv), delta_t(dt), packet(p) { }
        };
        std::list<PlayerHistory> player_hist;
 
index 5c06bbe6a0c115f8952fd19c3315a3b7da8cfb59..73931f44c1825ba166a743cafd53c8e9747e4d7c 100644 (file)
@@ -332,10 +332,11 @@ void NetworkedInput::PushPlayerUpdate(int dt) {
                InventorySlot()
        );
        if (player_hist.size() < 16) {
-               player_hist.emplace_back(state, dt, packet);
+               player_hist.emplace_back(state, GetPlayer().GetEntity().TargetVelocity(), dt, packet);
        } else {
                auto entry = player_hist.begin();
                entry->state = state;
+               entry->tgt_vel = GetPlayer().GetEntity().TargetVelocity();
                entry->delta_t = dt;
                entry->packet = packet;
                player_hist.splice(player_hist.end(), player_hist, entry);
@@ -378,6 +379,7 @@ void NetworkedInput::MergePlayerCorrection(uint16_t seq, const EntityState &corr
        vector<WorldCollision> col;
        while (entry != end) {
                replay.Velocity(entry->state.velocity);
+               replay.TargetVelocity(entry->tgt_vel);
                replay.Update(entry->delta_t);
                if (GetWorld().Intersection(replay, col)) {
                        GetWorld().Resolve(replay, col);
index 6a48874116dea291e82dc22b0d8097a3df3c0fa8..96386195e57803c4aa8fcd498072caa229df768f 100644 (file)
@@ -86,7 +86,7 @@ void PlayerController::UpdatePlayer() noexcept {
        constexpr float max_vel = 0.005f;
        if (dirty) {
                player.GetEntity().Orientation(glm::quat(glm::vec3(pitch, yaw, 0.0f)));
-               player.GetEntity().Velocity(glm::rotateY(move_dir * max_vel, yaw));
+               player.GetEntity().TargetVelocity(glm::rotateY(move_dir * max_vel, yaw));
 
                Ray aim = player.Aim();
                if (!world.Intersection(aim, glm::mat4(1.0f), player.GetEntity().ChunkCoords(), aim_world)) {
index eb312eee8d19417ac97995e0abdcb09afa8ece20..bf5fbe9db56bac383afcdcdac74c1e105120f99d 100644 (file)
@@ -15,6 +15,7 @@
 namespace blank {
 
 class DirectionalLighting;
+struct EntityDerivative;
 class Shape;
 
 class Entity {
@@ -37,6 +38,9 @@ public:
        bool WorldCollidable() const noexcept { return world_collision; }
        void WorldCollidable(bool b) noexcept { world_collision = b; }
 
+       const glm::vec3 &TargetVelocity() const noexcept { return tgt_vel; }
+       void TargetVelocity(const glm::vec3 &v) noexcept { tgt_vel = v; }
+
        const glm::vec3 &Velocity() const noexcept { return state.velocity; }
        void Velocity(const glm::vec3 &v) noexcept { state.velocity = v; }
 
@@ -82,6 +86,14 @@ public:
                if (model) model.Render(M, prog);
        }
 
+private:
+       EntityDerivative CalculateStep(
+               const EntityState &cur,
+               float dt,
+               const EntityDerivative &prev
+       ) const noexcept;
+       glm::vec3 ControlForce(const EntityState &) const noexcept;
+
 private:
        Instance model;
 
@@ -90,6 +102,7 @@ private:
 
        AABB bounds;
        EntityState state;
+       glm::vec3 tgt_vel;
 
        int ref_count;
 
diff --git a/src/world/EntityDerivative.hpp b/src/world/EntityDerivative.hpp
new file mode 100644 (file)
index 0000000..9666b1f
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef BLANK_WORLD_ENTITYDERIVATIVE_HPP_
+#define BLANK_WORLD_ENTITYDERIVATIVE_HPP_
+
+#include <glm/glm.hpp>
+
+
+namespace blank {
+
+struct EntityDerivative {
+
+       glm::vec3 position;
+       glm::vec3 velocity;
+       glm::vec3 orient;
+
+};
+
+}
+
+#endif
index 8f74114cb7de0ba2d681b362385698b4d31c77b8..e93fffa6714d324990c349f1b43d2e13c63f5827 100644 (file)
@@ -23,9 +23,6 @@ struct EntityState {
        /// make sure block_pos is within chunk bounds
        void AdjustPosition() noexcept;
 
-       /// do an integration step of dt milliseconds
-       void Update(int dt) noexcept;
-
        /// get a position vector relative to the (0,0,0) chunk
        glm::vec3 AbsolutePosition() const noexcept {
                return glm::vec3(chunk_pos * Chunk::Extent()) + block_pos;
index e4fb968ddfbb8014004a2b7a6a7647be53b2c2a5..8be2941c441e96b2fcfff49da8daec3f430a5f2a 100644 (file)
@@ -1,4 +1,5 @@
 #include "Entity.hpp"
+#include "EntityDerivative.hpp"
 #include "EntityState.hpp"
 #include "Player.hpp"
 #include "World.hpp"
@@ -12,6 +13,7 @@
 
 #include <algorithm>
 #include <cmath>
+#include <iostream>
 #include <limits>
 #include <glm/gtx/io.hpp>
 #include <glm/gtx/quaternion.hpp>
@@ -26,6 +28,7 @@ Entity::Entity() noexcept
 , name("anonymous")
 , bounds()
 , state()
+, tgt_vel(0.0f)
 , ref_count(0)
 , world_collision(false)
 , dead(false) {
@@ -68,7 +71,56 @@ glm::quat delta_rot(const glm::vec3 &av, float dt) {
 }
 
 void Entity::Update(int dt) noexcept {
-       state.Update(dt);
+       float fdt = float(dt);
+
+       // euler
+       //state.block_pos += state.velocity * fdt;
+       //state.velocity += ControlForce(state) * fdt;
+       //state.orient = delta_rot(state.ang_vel, fdt) * state.orient;
+       //state.AdjustPosition();
+
+       // RK4
+       EntityDerivative a(CalculateStep(state, 0.0f, EntityDerivative()));
+       EntityDerivative b(CalculateStep(state, fdt * 0.5f, a));
+       EntityDerivative c(CalculateStep(state, fdt * 0.5f, b));
+       EntityDerivative d(CalculateStep(state, fdt, c));
+
+       EntityDerivative f;
+       constexpr float sixth = 1.0f / 6.0f;
+       f.position = sixth * ((a.position + 2.0f * (b.position + c.position)) + d.position);
+       f.velocity = sixth * ((a.velocity + 2.0f * (b.velocity + c.velocity)) + d.velocity);
+       f.orient = sixth * ((a.orient + 2.0f * (b.orient + c.orient)) + d.orient);
+
+       state.block_pos += f.position * fdt;
+       state.velocity += f.velocity * fdt;
+       state.orient = delta_rot(f.orient, fdt) * state.orient;
+       state.AdjustPosition();
+}
+
+EntityDerivative Entity::CalculateStep(
+       const EntityState &cur,
+       float dt,
+       const EntityDerivative &delta
+) const noexcept {
+       EntityState next(cur);
+       next.block_pos += delta.position * dt;
+       next.velocity += delta.velocity * dt;
+       next.orient = delta_rot(cur.ang_vel, dt) * cur.orient;
+       next.AdjustPosition();
+
+       EntityDerivative out;
+       out.position = next.velocity;
+       out.velocity = ControlForce(next); // plus other forces and then by mass
+       return out;
+}
+
+glm::vec3 Entity::ControlForce(const EntityState &cur) const noexcept {
+       constexpr float k = 1.0f; // spring constant
+       constexpr float b = 1.0f; // damper constant
+       constexpr float t = 0.01f; // 1/time constant
+       const glm::vec3 x(-tgt_vel); // endpoint displacement from equilibrium
+       const glm::vec3 v(cur.velocity); // relative velocity between endpoints
+       return (((-k) * x) - (b * v)) * t; // times mass = 1
 }
 
 
@@ -81,13 +133,6 @@ EntityState::EntityState()
 
 }
 
-void EntityState::Update(int dt) noexcept {
-       float fdt = float(dt);
-       block_pos += velocity * fdt;
-       orient = delta_rot(ang_vel, fdt) * orient;
-       AdjustPosition();
-}
-
 void EntityState::AdjustPosition() noexcept {
        while (block_pos.x >= Chunk::width) {
                block_pos.x -= Chunk::width;