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);
}
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));
}
}
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);
}
}
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;
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);
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);
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)) {
namespace blank {
class DirectionalLighting;
+struct EntityDerivative;
class Shape;
class Entity {
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; }
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;
AABB bounds;
EntityState state;
+ glm::vec3 tgt_vel;
int ref_count;
--- /dev/null
+#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
/// 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;
#include "Entity.hpp"
+#include "EntityDerivative.hpp"
#include "EntityState.hpp"
#include "Player.hpp"
#include "World.hpp"
#include <algorithm>
#include <cmath>
+#include <iostream>
#include <limits>
#include <glm/gtx/io.hpp>
#include <glm/gtx/quaternion.hpp>
, name("anonymous")
, bounds()
, state()
+, tgt_vel(0.0f)
, ref_count(0)
, world_collision(false)
, dead(false) {
}
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
}
}
-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;