LANTERN feel pass (DR-052 + gap list): SoD facing, underwater feel, Bathynaut kit, walk/run gait, suit lamp + new Synty anim packs
- SoD facing: PlayerFacing = body-yaw only (move-facing / cast-turn / idle-hold); every fire direction re-sourced to FacingMath.ResolveAim (pre-code review blocking catch); TickWindowMath shared windows with Movement-skip; reticle/FX coupled to the damage direction; cursor-dash kept. - Underwater feel: sharpness 15->6, turn 720->360, MoveSpeed 6->4.2; TuningKnob 26-28 (0 = no-override sentinels, dev-protocol bump on DebugTuningReport); stride footsteps + silt + cadence floor; bubbles; underwater ambience bed + distant groans; camera drag + dev scroll zoom. - Bathynaut kit in-engine: dome/tank/shoulder-lamp + bare head grafted (GraftSmr rigid rebase, RecalculateTangents); EmissiveGloamSkinned shader (Rukhanka deformation); shoulder lamp CASTS (warm steady spot on body yaw). - Gait: two-ring walk/run FreeformDirectional tree (walk @0.35, run @1.0) + blended-natural StrideScale; additive Posture(Bank) + Lead(chest-lead) layers; idle = AnimationIdles Base; banking driven from facing turn rate; flat terrain (Env_SeabedKit seabed squashed - CC is planar). - New packs: Synty AnimationIdles + AnimationSwordCombat (combat pass queued) + SyntyPropBoneTool; four authored clips (sway/trudge/banks/lean) + Anim_Player_Underwater.blend + suit-kit FBX. - Validation: 411/411 EditMode green; Play smokes (server==client facing, Aim-true projectile, bank/stride live-sampled, lamp beam verified); pre-code + post-impl adversarial reviews applied. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace ProjectM.Simulation
|
||||
{
|
||||
/// <summary>
|
||||
/// Pure facing/aim math for the Shape-of-Dreams facing model (body yaw follows movement; turns toward
|
||||
/// the aim only inside a cast window; holds when idle; the cursor is never passively tracked).
|
||||
/// RotateToward is the verbatim extraction of PlayerAimSystem's rate-limited planar turn so it stays
|
||||
/// the tested-in-play math. ResolveAim is THE gameplay fire-direction resolver — every damage/spawn
|
||||
/// direction (AbilityFireSystem archetypes, MeleeComboSystem cleave) and the aim-readout presentation
|
||||
/// (reticle, local slash arcs) must route through it so sim and FX can never diverge. EditMode-tested,
|
||||
/// Burst-safe, no World needed.
|
||||
/// </summary>
|
||||
public static class FacingMath
|
||||
{
|
||||
/// <summary>Gameplay fire direction: raw replicated Aim when meaningful, else the current body facing
|
||||
/// (resting gamepad right stick — preserves controller-first "zero aim = movement heading" because
|
||||
/// facing tracks Move under the SoD model), else world +Z. Always normalized.</summary>
|
||||
public static float2 ResolveAim(float2 aim, float2 facing)
|
||||
{
|
||||
if (math.lengthsq(aim) > 1e-6f) return math.normalize(aim);
|
||||
if (math.lengthsq(facing) > 1e-6f) return math.normalize(facing);
|
||||
return new float2(0f, 1f);
|
||||
}
|
||||
|
||||
/// <summary>The shared Aim→Move→hold cascade. castActive grants Aim PRIORITY only — a zero Aim
|
||||
/// (resting gamepad stick mid-cast) falls through to Move, then to "no target" (hold previous
|
||||
/// facing). Returns false when there is no target this tick.</summary>
|
||||
public static bool SelectTarget(bool castActive, float2 aim, float2 move, out float2 target)
|
||||
{
|
||||
if (castActive && math.lengthsq(aim) > 1e-6f)
|
||||
{
|
||||
target = math.normalize(aim);
|
||||
return true;
|
||||
}
|
||||
if (math.lengthsq(move) > 1e-6f)
|
||||
{
|
||||
target = math.normalize(move);
|
||||
return true;
|
||||
}
|
||||
target = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>Rate-limited planar rotate toward a normalized target: snaps when uninitialized or within
|
||||
/// reach this step, else rotates by maxStepRadians toward the target. Deterministic pure math
|
||||
/// (fixed-step dt at the caller) so it replays identically on rollback re-simulation.</summary>
|
||||
public static float2 RotateToward(float2 current, float2 target, float maxStepRadians)
|
||||
{
|
||||
if (math.lengthsq(current) < 1e-6f)
|
||||
return target; // uninitialized facing -> snap to target
|
||||
|
||||
float2 cur = math.normalize(current);
|
||||
float angle = math.acos(math.clamp(math.dot(cur, target), -1f, 1f));
|
||||
if (angle <= maxStepRadians)
|
||||
return target; // within reach this step
|
||||
|
||||
float sign = (cur.x * target.y - cur.y * target.x) >= 0f ? 1f : -1f;
|
||||
math.sincos(maxStepRadians * sign, out float sn, out float cs);
|
||||
return math.normalize(new float2(cur.x * cs - cur.y * sn, cur.x * sn + cur.y * cs));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user