Files
brandling-safari/shared/Movement.h
Gabe 238cd9c6c3 Brandling Safari: LAN safari-zone creature catching on the HD-2D engine
- Authoritative 30 Hz server (ENet, SQLite): accounts, characters, wild AI, tall grass /
  water / wandering spawns, fishing, captures, follower chains, clock + weather, LAN beacon
- Client: title / join / character creator / play screens, prediction + reconciliation,
  interpolated players and parties, HD-2D UI (dialogue with Professor Henry, HUD, collection)
- Shared deterministic zone generator, movement, protocol, roster, appearance
- Paper-doll character art pipeline (PixelLab base walk + per-item animation edits)
- Brandling roster from the company list (logo colors, jev types), Blender safari props
- Headless test bot
2026-10-02 15:20:27 -05:00

50 lines
1.6 KiB
C++

#pragma once
// Player movement, run identically by the server (authoritative) and the
// client (prediction + reconciliation). Pure function of state + input.
#include "Protocol.h"
#include "Zone.h"
namespace bs {
constexpr float kWalkSpeed = 4.0f; // world units / second
constexpr float kRunSpeed = 6.6f;
struct MoveState {
glm::vec2 pos{0.0f};
float yaw = 0.0f;
bool moving = false;
bool running = false;
};
inline void stepMovement(const Zone& zone, MoveState& s, const InputCmd& in, float dt) {
glm::vec2 dir = in.move();
float amount = std::min(glm::length(dir), 1.0f);
s.moving = amount > 0.05f;
s.running = s.moving && in.run();
if (!s.moving) return;
dir = glm::normalize(dir) * amount;
s.yaw = yawFromDir(dir);
glm::vec2 step = dir * (s.running ? kRunSpeed : kWalkSpeed) * dt;
// Axis-separated resolution slides along obstacles.
glm::vec2 p = s.pos;
if (zone.walkable(p, p + glm::vec2(step.x, 0.0f))) p.x += step.x;
if (zone.walkable(p, p + glm::vec2(0.0f, step.y))) p.y += step.y;
s.pos = p;
}
// Quantizes a world direction exactly like the network does, so prediction
// uses the same input the server will see.
inline InputCmd makeInput(uint32_t seq, glm::vec2 worldDir, bool run) {
InputCmd c;
c.seq = seq;
float len = glm::length(worldDir);
if (len > 1.0f) worldDir /= len;
c.moveX = int8_t(std::lround(glm::clamp(worldDir.x, -1.0f, 1.0f) * 127.0f));
c.moveZ = int8_t(std::lround(glm::clamp(worldDir.y, -1.0f, 1.0f) * 127.0f));
c.flags = run ? 1 : 0;
return c;
}
} // namespace bs