feat(physics): L.3a — wall-bounce velocity reflection on airborne hits
Three independent research agents converged: retail's "bouncy walls" feel comes from CPhysicsObj::handle_all_collisions (acclient_2013_pseudo_c.txt: 282699-282715, ACE PhysicsObj.cs:2692-2697) which applies the canonical reflection v_new = v - (1 + e) * dot(v, n) * n to the body's velocity after every transition resolves. Player elasticity = 0.05 (5% bounce); INELASTIC_PS = 0x20000 zeros velocity entirely (used by spell projectiles). acdream had the data plumbed (PhysicsBody.Elasticity = 0.05 was already set, ci.CollisionNormal was being populated in 8+ code paths) but ResolveWithTransition discarded the normal before returning. Hence "sticky walls on jumps" — perpendicular velocity got removed by SlideSphere's geometric resolution, but never reflected back, so hitting a wall mid-jump zeroed forward motion entirely instead of producing a small push-back. Files: - PhysicsBody.cs: add PhysicsStateFlags.Inelastic = 0x20000. - ResolveResult.cs: surface CollisionNormalValid + CollisionNormal. - PhysicsEngine.cs:599-624: copy ci.CollisionNormal into ResolveResult before returning (both ok and partial paths). - PlayerMovementController.cs:445-503: after position commit, apply reflection per the retail formula. Inelastic → zero velocity; else → reflect with v += n * -(dot(v,n) * (e + 1)). apply_bounce rule (more conservative than retail by design): - Sledding: retail's strict rule — bounce unless both grounded. - Otherwise: bounce ONLY when both prev and now airborne. Suppress on landing (prev air, now ground) to avoid micro-bouncing on floor — the post-reflection upward Z defeats the controller's Velocity.Z<=0 landing-snap gate. Retail's elasticity 0.05 makes the artifact visually imperceptible there; acdream's per-frame architecture amplifies it. Tests: 1491 → 1491 still pass (existing AirborneFrames + WalkOffLedge tests confirmed the conservative apply_bounce rule keeps landings clean). Live verification needed: jump into a wall mid-air — should produce a visible bounce-back rather than sticking. Walking along corridor with side-clip should still slide. Landing should still settle without micro-bounce. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
261322b48e
commit
a1c27b3afb
4 changed files with 191 additions and 3 deletions
|
|
@ -31,6 +31,14 @@ public enum PhysicsStateFlags : uint
|
|||
ReportCollisions = 0x00000010,
|
||||
Gravity = 0x00000400, // bit 10 — apply downward gravity
|
||||
Hidden = 0x00001000,
|
||||
/// <summary>
|
||||
/// L.3a (2026-04-30): retail INELASTIC_PS bit (acclient.h:2834).
|
||||
/// When set, wall-collisions zero the velocity instead of reflecting.
|
||||
/// Used by spell projectiles and missiles that should embed/explode on
|
||||
/// impact rather than bounce. The player NEVER has this flag set —
|
||||
/// player wall-hits use the reflection path with elasticity ~0.05.
|
||||
/// </summary>
|
||||
Inelastic = 0x00020000, // bit 17 — retail INELASTIC_PS
|
||||
Sledding = 0x00800000, // bit 23 — sledding (modified friction)
|
||||
}
|
||||
|
||||
|
|
@ -44,6 +52,7 @@ public enum TransientStateFlags : uint
|
|||
None = 0,
|
||||
Contact = 0x00000001, // bit 0 — touching any surface
|
||||
OnWalkable = 0x00000002, // bit 1 — standing on a walkable surface
|
||||
Sliding = 0x00000004, // bit 2 — carry sliding normal into next transition
|
||||
Active = 0x00000080, // bit 7 — object needs per-frame update
|
||||
}
|
||||
|
||||
|
|
@ -87,6 +96,9 @@ public sealed class PhysicsBody
|
|||
/// <summary>Ground contact-plane normal (+0x130/134/138).</summary>
|
||||
public Vector3 GroundNormal { get; set; } = Vector3.UnitZ;
|
||||
|
||||
/// <summary>Last wall/object sliding normal (retail transient Sliding state).</summary>
|
||||
public Vector3 SlidingNormal { get; set; }
|
||||
|
||||
// ── persisted contact-plane state (retail PhysicsObj fields) ───────────
|
||||
//
|
||||
// Retail's PhysicsObj carries its last contact plane FORWARD across frames.
|
||||
|
|
@ -113,6 +125,18 @@ public sealed class PhysicsBody
|
|||
/// <summary>Whether the contact plane is a water surface (affects step behavior).</summary>
|
||||
public bool ContactPlaneIsWater { get; set; }
|
||||
|
||||
/// <summary>Whether the previous walkable polygon is available for edge slide.</summary>
|
||||
public bool WalkablePolygonValid { get; set; }
|
||||
|
||||
/// <summary>Most recent walkable polygon plane (world-space).</summary>
|
||||
public System.Numerics.Plane WalkablePlane { get; set; }
|
||||
|
||||
/// <summary>Most recent walkable polygon vertices (world-space).</summary>
|
||||
public Vector3[]? WalkableVertices { get; set; }
|
||||
|
||||
/// <summary>Up vector used by the most recent walkable polygon probe.</summary>
|
||||
public Vector3 WalkableUp { get; set; } = Vector3.UnitZ;
|
||||
|
||||
/// <summary>Elasticity coefficient (+0xB0).</summary>
|
||||
public float Elasticity { get; set; } = 0.05f;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue