feat(creatures): refine pig movement physics

Add movement constants for pigs and switch deceleration to per-axis friction so creatures stop naturally. Extend wander boost duration for smoother behavior.
This commit is contained in:
2026-08-02 16:36:56 +08:00
parent 9bb1882d92
commit 5980400e2e
6 changed files with 35 additions and 30 deletions

View File

@@ -3,4 +3,11 @@
namespace Cubed {
struct PigTag {};
namespace PigDefaults {
constexpr float MAX_SPEED = 0.1f; // tiles/tick → 2 tiles/sec
constexpr float ACCELERATION = 0.01f; // ~10 ticks (0.5s) to reach full speed
constexpr float DECELERATION = 0.02f; // ~5 ticks (0.25s) to stop
constexpr float GRAVITY = 1.0f; // ≈20 tiles/s², close to the player
} // namespace PigDefaults
} // namespace Cubed

View File

@@ -1,14 +1,12 @@
#pragma once
#include "Cubed/gameplay/ecs/movement.hpp"
#include "Cubed/gameplay/ecs/transform.hpp"
#include <entt/entt.hpp>
namespace Cubed {
class ServerWorld;
class PhysicalSystem {
public:
static glm::vec3 get_move_distance(const Direction& d,
const TickVelocity& v);
static glm::vec3 get_move_distance(const TickVelocity& v);
static void update(ServerWorld& world, entt::registry& registry);

View File

@@ -20,9 +20,10 @@ void ServerEntityManager::init() {
m_factories.try_emplace("cubed:pig", [this]() {
BaseServerCreature c;
c.hitbox = HitboxManager::instance().get_hitbox_id("cubed:pig");
c.gravity.value = 1.0f;
c.movement.acceleration = 1.0f;
c.movement.deceleration = 1.0f;
c.gravity.value = PigDefaults::GRAVITY;
c.movement.acceleration = PigDefaults::ACCELERATION;
c.movement.deceleration = PigDefaults::DECELERATION;
c.velocity.max.x = c.velocity.max.z = PigDefaults::MAX_SPEED;
return create_entity_in_factory(
Entity{m_next}, EntityInfo{"cubed:pig", ""}, std::move(c), PigTag{},
AIBase{}, WanderAITag{}, MoveBoost{});

View File

@@ -107,8 +107,7 @@ void PhysicalSystem::update(ServerWorld& world, entt::registry& registry) {
auto view = registry.view<BaseServerCreature>();
for (auto e : view) {
auto& creature = view.get<BaseServerCreature>(e);
auto distance =
get_move_distance(creature.direction, creature.velocity);
auto distance = get_move_distance(creature.velocity);
auto box = HitboxManager::hitbox(creature.hitbox);
auto& pos = creature.transform.position.value;
auto& v = creature.velocity;
@@ -135,8 +134,7 @@ void PhysicalSystem::update(ServerWorld& world, entt::registry& registry) {
}
}
glm::vec3 PhysicalSystem::get_move_distance(const Direction& d,
const TickVelocity& v) {
return glm::vec3{d.value.x * v.value.x, v.value.y, d.value.z * v.value.z};
glm::vec3 PhysicalSystem::get_move_distance(const TickVelocity& v) {
return v.value; // Per-tick forward distance equals the velocity magnitud
}
} // namespace Cubed

View File

@@ -10,31 +10,31 @@ void SpeedSystem::update(float dt, entt::registry& registry) {
for (auto e : view) {
auto [creature, moveboost] = view.get<BaseServerCreature, MoveBoost>(e);
auto& v = creature.velocity.value;
if (moveboost.count <= moveboost.duration) {
++moveboost.count;
creature.velocity.value +=
creature.direction.value * creature.movement.acceleration;
} else if (glm::dot(creature.velocity.value, creature.velocity.value) >=
0.001f) {
creature.velocity.value -=
creature.direction.value * creature.movement.deceleration;
v += creature.direction.value * creature.movement.acceleration;
} else {
creature.velocity.value = glm::vec3(0.0f);
}
creature.velocity.value.y += -creature.gravity.value * dt;
auto v_clamp = [](float& v, float max) {
if (max < 0.0f) {
return;
}
auto sign = v < 0.0f ? -1.0f : 1.0f;
v = sign * std::clamp(std::abs(v), 0.0f, max);
if (v < 0.0f) {
v = 0.0f;
}
// Decelerated by friction in all directions
auto decay = [](float& c, float d) {
if (c > 0.0f)
c = std::max(0.0f, c - d);
else if (c < 0.0f)
c = std::min(0.0f, c + d);
};
v_clamp(creature.velocity.value.x, creature.velocity.max.x);
v_clamp(creature.velocity.value.y, creature.velocity.max.y);
v_clamp(creature.velocity.value.z, creature.velocity.max.z);
decay(v.x, creature.movement.deceleration);
decay(v.z, creature.movement.deceleration);
}
v.y += -creature.gravity.value * dt;
auto v_clamp = [](float& c, float max) {
if (max < 0.0f) {
return; //-1 = unlimited
}
c = std::clamp(c, -max, max);
};
v_clamp(v.x, creature.velocity.max.x);
v_clamp(v.y, creature.velocity.max.y);
v_clamp(v.z, creature.velocity.max.z);
}
}

View File

@@ -32,7 +32,8 @@ void WanderAISystem::do_ai(BaseServerCreature& creature,
creature.direction.value = r.random_direction_horizontal();
}
if (r.random_bool(MOVE_PROBABILITY)) {
move_boost.duration = r.random_int(5, 8);
move_boost.duration = r.random_int(20, 40);
move_boost.count = 0;
}
}