feat(physics): port full CTransition collision response from pseudocode
Replace simplified push-out with retail-faithful SlideSphere and AdjustOffset from transition_pseudocode.md. Crease-projection between collision normal and contact plane produces smooth wall-sliding. Object collision uses proper rotation transform to object-local space. SlideSphere (section 6): computes crease direction via cross product of collision normal and contact plane normal, projects displacement onto the crease, then applies the correction offset. Handles three cases: crease exists, parallel same-direction, parallel opposing. AdjustOffset (section 6): adds safety check to keep sphere above contact plane by computing signed distance and pushing up along Z when the sphere dips below. FindObjCollisions: removes ad-hoc penetration push-out, now calls SlideSphere after BSP hit detection for proper wall-slide behavior. Also fixes: ShadowEntry gains Rotation field, tests updated to match Register signature, unused variables removed from GameWindow. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e2f0c8580e
commit
e12d255d2e
4 changed files with 182 additions and 84 deletions
|
|
@ -20,14 +20,12 @@ public sealed class ShadowObjectRegistry
|
|||
/// <summary>
|
||||
/// Register an entity into the cells it overlaps based on world position + radius.
|
||||
/// </summary>
|
||||
public void Register(uint entityId, uint gfxObjId, Vector3 worldPos, float radius,
|
||||
float worldOffsetX, float worldOffsetY, uint landblockId)
|
||||
public void Register(uint entityId, uint gfxObjId, Vector3 worldPos, Quaternion rotation,
|
||||
float radius, float worldOffsetX, float worldOffsetY, uint landblockId)
|
||||
{
|
||||
// Deregister first if already registered (handles position updates)
|
||||
Deregister(entityId);
|
||||
|
||||
// Compute which cells the entity's bounding sphere overlaps.
|
||||
// Each cell is 24×24m within a 192m landblock.
|
||||
float localX = worldPos.X - worldOffsetX;
|
||||
float localY = worldPos.Y - worldOffsetY;
|
||||
|
||||
|
|
@ -36,7 +34,7 @@ public sealed class ShadowObjectRegistry
|
|||
int minCy = Math.Max(0, (int)((localY - radius) / 24f));
|
||||
int maxCy = Math.Min(7, (int)((localY + radius) / 24f));
|
||||
|
||||
var entry = new ShadowEntry(entityId, gfxObjId, worldPos, radius);
|
||||
var entry = new ShadowEntry(entityId, gfxObjId, worldPos, rotation, radius);
|
||||
var cellIds = new List<uint>();
|
||||
|
||||
uint lbPrefix = landblockId & 0xFFFF0000u;
|
||||
|
|
@ -148,4 +146,9 @@ public sealed class ShadowObjectRegistry
|
|||
public int TotalRegistered => _entityToCells.Count;
|
||||
}
|
||||
|
||||
public readonly record struct ShadowEntry(uint EntityId, uint GfxObjId, Vector3 Position, float Radius);
|
||||
public readonly record struct ShadowEntry(
|
||||
uint EntityId,
|
||||
uint GfxObjId,
|
||||
Vector3 Position,
|
||||
Quaternion Rotation,
|
||||
float Radius);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue