59#include <glm/trigonometric.hpp>
150inline void dirToYawPitch(
const glm::vec3& dir,
float& outYaw,
float& outPitch)
152 outYaw = std::atan2(dir.x, dir.z);
153 outPitch = -std::asin(std::clamp(dir.y, -1.0f, 1.0f));
157inline float coneFalloff(
float angleRad,
float innerRad,
float outerRad)
159 if (angleRad <= innerRad)
161 if (angleRad >= outerRad)
163 return (outerRad - angleRad) / (outerRad - innerRad);
170 const glm::vec3& eye,
const glm::vec3& dir,
const glm::vec3& aabbMin,
const glm::vec3& aabbMax,
float fallbackDist)
175 float tEnter = -std::numeric_limits<float>::infinity();
176 float tExit = std::numeric_limits<float>::infinity();
178 for (
int i = 0; i < 3; ++i) {
179 if (std::fabs(dir[i]) < 1e-6f) {
180 if (eye[i] < aabbMin[i] || eye[i] > aabbMax[i]) {
185 float t1 = (aabbMin[i] - eye[i]) / dir[i];
186 float t2 = (aabbMax[i] - eye[i]) / dir[i];
189 tEnter = std::max(tEnter, t1);
190 tExit = std::min(tExit, t2);
191 if (tEnter > tExit) {
197 if (hits && tEnter >= 0.0f) {
198 return eye + dir * tEnter;
203 const glm::vec3 raySample = eye + dir * fallbackDist;
204 return glm::clamp(raySample, aabbMin, aabbMax);
241 const float moveStickMag = std::sqrt(lx * lx + ly * ly);
242 const float lookStickMag = std::sqrt(rx * rx + ry * ry);
254 entt::entity localEntity = entt::null;
256 float curYaw = 0.0f, curPitch = 0.0f;
257 bool foundLocal =
false;
265 const float eyeOffset = shape.
halfExtents.y * 0.77f;
267 eye = pos.
value + glm::vec3{0.0f, eyeOffset * aaEyeDir, 0.0f};
269 curPitch = snap.
pitch;
276 const float cosPitchInit = std::cos(curPitch);
277 const glm::vec3 camFwd{std::sin(curYaw) * cosPitchInit, -std::sin(curPitch), std::cos(curYaw) * cosPitchInit};
285 entt::entity bestTarget = entt::null;
286 glm::vec3 bestTargetPos{0.0f};
287 glm::vec3 bestHalfExtents{0.0f};
295 if (e == localEntity)
302 const glm::vec3 toCentre = pos.
value - eye;
303 const float dist = glm::length(toCentre);
304 if (dist < 1e-3f || dist > cfg.
maxRange)
307 const glm::vec3 dirToCentre = toCentre / dist;
308 const float dot = glm::clamp(glm::dot(camFwd, dirToCentre), -1.0f, 1.0f);
312 const float angle = std::acos(dot);
313 if (angle >= bestAngle)
324 bestTargetPos = pos.
value;
329 if (bestTarget == entt::null) {
337 const float coneFactor =
340 const float distFactor = 1.0f - std::clamp(bestDist / cfg.
maxRange, 0.0f, 1.0f);
344 const float strength = coneFactor * distFactor;
346 if (coneFactor <= 0.0f) {
355 const glm::vec3 aaHalfExtents{
356 std::min(bestHalfExtents.x, 18.0f), bestHalfExtents.y, std::min(bestHalfExtents.z, 18.0f)};
357 const glm::vec3 aabbMin = bestTargetPos - aaHalfExtents;
358 const glm::vec3 aabbMax = bestTargetPos + aaHalfExtents;
361 const bool switchedTarget = (state.
lastTarget != bestTarget);
375 const glm::vec3 dirToTarget = glm::normalize(bestTargetPos - eye);
376 float targetYaw = 0.0f, targetPitch = 0.0f;
378 const float dYawToTarget = std::remainder(targetYaw - curYaw, glm::radians(360.0f));
379 const float dPitchToTarget = targetPitch - curPitch;
389 const float stickYaw = -rx;
390 const float stickPitch = ry;
392 const float stickLen = std::sqrt(stickYaw * stickYaw + stickPitch * stickPitch);
393 const float targetOffsetLen = std::sqrt(dYawToTarget * dYawToTarget + dPitchToTarget * dPitchToTarget);
396 if (stickLen > 1e-4f && targetOffsetLen > 1e-4f) {
399 dirDot = (stickYaw * dYawToTarget + stickPitch * dPitchToTarget) / (stickLen * targetOffsetLen);
400 dirDot = std::clamp(dirDot, -1.0f, 1.0f);
407 const float proximity = 1.0f - std::clamp(bestAngle / outerRad, 0.0f, 1.0f);
408 const float proxCurve = proximity * proximity;
424 effectiveSlowdown = std::clamp(effectiveSlowdown, 0.0f, 1.0f);
426 const float refund = (1.0f - effectiveSlowdown) * strength;
427 snap.
yaw += rx * lookSens * dt * refund;
428 snap.
pitch -= ry * lookSens * dt * refund;
444 const glm::vec3 curAnchorWorld = bestTargetPos + state.
anchorLocal;
446 const glm::vec3 dirPrev = glm::normalize(prevAnchorWorld - state.
lastEye);
447 const glm::vec3 dirCur = glm::normalize(curAnchorWorld - eye);
449 float yawPrev = 0.0f, pitchPrev = 0.0f, yawCur = 0.0f, pitchCur = 0.0f;
454 const float dYaw = std::remainder(yawCur - yawPrev, glm::radians(360.0f));
455 const float dPitch = pitchCur - pitchPrev;
464 const float yawPull =
466 const float pitchPull =
469 snap.
pitch += pitchPull;
472 snap.
yaw = std::remainder(snap.
yaw, glm::radians(360.0f));
473 snap.
pitch = std::clamp(snap.
pitch, -glm::radians(89.0f), glm::radians(89.0f));
482 float updatedYaw = curYaw, updatedPitch = curPitch;
484 updatedYaw = snap.
yaw;
485 updatedPitch = snap.
pitch;
487 const float cosUpdated = std::cos(updatedPitch);
488 const glm::vec3 camFwdAfter{
489 std::sin(updatedYaw) * cosUpdated, -std::sin(updatedPitch), std::cos(updatedYaw) * cosUpdated};
AABB collision shape component for physics entities.
Client side Tag component — entity is eligible to receive player input.
Marker component identifying the locally controlled player entity.
Visible / replicated half of the player locomotion state.
World-space position component for ECS entities.
Shared hitscan raycasting against world geometry and player hitboxes.
Shared ECS registry type alias for the game engine.
entt::registry Registry
Shared ECS registry type alias.
Definition Registry.hpp:11
Component for tracking player respawn times.
Shared world geometry for collision / movement / raycast systems.
const WorldGeometry & activeWorld()
Return the world geometry most recently set via setActiveWorld(), or fall back to testWorld() if none...
Definition WorldData.hpp:236
HitscanHit raycastWorld(glm::vec3 origin, glm::vec3 direction, const WorldGeometry &world)
Raycast against all static world geometry (planes + boxes + cylinders + spheres).
Definition Raycast.hpp:370
Definition GamepadAimAssistSystem.hpp:145
float coneFalloff(float angleRad, float innerRad, float outerRad)
Linear cone falloff: 1.0 inside innerRad, 0.0 outside outerRad.
Definition GamepadAimAssistSystem.hpp:157
glm::vec3 rayOntoAABB(const glm::vec3 &eye, const glm::vec3 &dir, const glm::vec3 &aabbMin, const glm::vec3 &aabbMax, float fallbackDist)
Find the world point where the camera ray hits the target's AABB, or — if it misses — the closest poi...
Definition GamepadAimAssistSystem.hpp:169
void dirToYawPitch(const glm::vec3 &dir, float &outYaw, float &outPitch)
Convert a world-space direction into yaw/pitch matching the renderer convention used by cachedCamFwd_...
Definition GamepadAimAssistSystem.hpp:150
Definition InputSampleSystem.hpp:173
float normaliseAxis(Sint16 raw)
Convert SDL's int16 axis value to a deadzoned float in [-1, 1].
Definition InputSampleSystem.hpp:192
Client-only input sampling system — split into two halves so mouse look can run every iterate() (smoo...
Definition DebugUI.hpp:15
void runGamepadAimAssist(Registry ®istry, SDL_Gamepad *gamepad, const GamepadAimAssistConfig &cfg, GamepadAimAssistState &state, float lookSens, float dt)
Apply gamepad aim assist (slowdown + movement-tracking pull) to the local player's InputSnapshot.
Definition GamepadAimAssistSystem.hpp:219
Axis-aligned bounding box defined by half-extents from the entity's Position.
Definition CollisionShape.hpp:16
glm::vec3 halfExtents
AABB half-dimensions (units).
Definition CollisionShape.hpp:17
Client side Tag component — entity is eligible to receive player input.
Definition Controllable.hpp:9
Marker component that tags exactly one entity per client as the locally controlled player.
Definition LocalPlayer.hpp:12
Replicated subset of player locomotion state.
Definition PlayerVisState.hpp:39
bool gravityFlipped
True when the player's gravity is inverted (walking on ceilings).
Definition PlayerVisState.hpp:54
bool isDead
True while the player is dead and waiting to respawn.
Definition PlayerVisState.hpp:46
World-space position of an entity, in game units.
Definition Position.hpp:10
glm::vec3 value
XYZ position (Y-up, Quake units).
Definition Position.hpp:11
ECS component: countdown until a dead player respawns.
Definition RespawnTimer.hpp:10
Result of a hitscan raycast.
Definition Raycast.hpp:34
bool hit
Definition Raycast.hpp:35
float distance
Definition Raycast.hpp:36
Tunable parameters for gamepad aim assist.
Definition GamepadAimAssistSystem.hpp:71
float slowdownStrength
Slowdown factor (0..1).
Definition GamepadAimAssistSystem.hpp:116
float activationStickThresh
Stick activation threshold (0..1 fraction of full deflection).
Definition GamepadAimAssistSystem.hpp:88
float innerConeDeg
Inner cone (degrees from crosshair) where pull strength is at maximum.
Definition GamepadAimAssistSystem.hpp:76
float maxPullRate
Hard cap on rotational pull this frame, in radians/second.
Definition GamepadAimAssistSystem.hpp:106
float rotationalCompensation
Tracking compensation factor.
Definition GamepadAimAssistSystem.hpp:100
float maxRange
Maximum world distance to a target at which aim assist applies.
Definition GamepadAimAssistSystem.hpp:83
bool enabled
Definition GamepadAimAssistSystem.hpp:72
float outerConeDeg
Outer cone (degrees from crosshair) where pull falls to zero.
Definition GamepadAimAssistSystem.hpp:80
Per-frame state required to compute the rotational pull as a delta between frames.
Definition GamepadAimAssistSystem.hpp:123
glm::vec3 anchorLocal
Anchor offset from the target's Position.value in world axes.
Definition GamepadAimAssistSystem.hpp:130
glm::vec3 lastEye
Local player's eye position last frame.
Definition GamepadAimAssistSystem.hpp:137
bool initialised
False until we have one completed frame of history for the current target.
Definition GamepadAimAssistSystem.hpp:141
glm::vec3 lastTargetPos
Target's world position last frame — combined with the (then-) anchorLocal to recover where the ancho...
Definition GamepadAimAssistSystem.hpp:133
entt::entity lastTarget
Target locked-onto last frame (entt::null when none).
Definition GamepadAimAssistSystem.hpp:126