feat(physics): PositionManager combiner class + 6 unit tests (L.3.2)
Pure-function ComputeOffset(dt, pos, seqVel, ori, interp, maxSpeed) → Vector3. Combines animation root motion (seqVel × dt rotated by body orientation) with InterpolationManager.AdjustOffset world-space correction. Mirrors retail CPhysicsObj::UpdateObjectInternal (acclient @ 0x00513730). Composed into RemoteMotion in subsequent task (L.3.1+L.3.2 Task 3); not yet consumed. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
d063ac884d
commit
08fbbef3c4
2 changed files with 234 additions and 0 deletions
55
src/AcDream.Core/Physics/PositionManager.cs
Normal file
55
src/AcDream.Core/Physics/PositionManager.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
using System.Numerics;
|
||||
|
||||
namespace AcDream.Core.Physics;
|
||||
|
||||
/// <summary>
|
||||
/// Per-frame combiner for remote-entity motion: animation root motion
|
||||
/// + InterpolationManager catch-up correction. Pure function — no
|
||||
/// side effects, no hidden state.
|
||||
///
|
||||
/// Mirrors retail CPhysicsObj::UpdateObjectInternal (acclient @ 0x00513730):
|
||||
/// rootOffset = CPartArray::Update(dt) // animation
|
||||
/// PositionManager::adjust_offset(rootOffset) // adds correction
|
||||
/// frame.origin += rootOffset
|
||||
///
|
||||
/// In acdream the animation root motion is sourced from
|
||||
/// AnimationSequencer.CurrentVelocity (body-local velocity from the
|
||||
/// active locomotion cycle). We rotate that by the body's orientation
|
||||
/// to get a world-space delta, then add the InterpolationManager's
|
||||
/// world-space correction.
|
||||
/// </summary>
|
||||
public sealed class PositionManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Compute the per-frame world-space delta to add to body.Position.
|
||||
/// </summary>
|
||||
/// <param name="dt">Per-frame delta time, seconds.</param>
|
||||
/// <param name="currentBodyPosition">Body's current world-space position.</param>
|
||||
/// <param name="seqVel">
|
||||
/// Body-local velocity from the active animation cycle
|
||||
/// (from <c>AnimationSequencer.CurrentVelocity</c>); pass
|
||||
/// <c>Vector3.Zero</c> if the entity has no sequencer or is on a
|
||||
/// non-locomotion cycle.
|
||||
/// </param>
|
||||
/// <param name="ori">Body orientation; used to rotate seqVel from body-local to world.</param>
|
||||
/// <param name="interp">The remote's InterpolationManager (for AdjustOffset call).</param>
|
||||
/// <param name="maxSpeed">From <c>MotionInterpreter.GetMaxSpeed()</c> — passed to AdjustOffset for the catch-up clamp.</param>
|
||||
public Vector3 ComputeOffset(
|
||||
double dt,
|
||||
Vector3 currentBodyPosition,
|
||||
Vector3 seqVel,
|
||||
Quaternion ori,
|
||||
InterpolationManager interp,
|
||||
float maxSpeed)
|
||||
{
|
||||
// Step 1: animation root motion (body-local → world).
|
||||
Vector3 rootMotionLocal = seqVel * (float)dt;
|
||||
Vector3 rootMotionWorld = Vector3.Transform(rootMotionLocal, ori);
|
||||
|
||||
// Step 2: interpolation correction (world-space already).
|
||||
Vector3 correction = interp.AdjustOffset(dt, currentBodyPosition, maxSpeed);
|
||||
|
||||
// Step 3: combined delta.
|
||||
return rootMotionWorld + correction;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue