fix(physics): #32 L.2c precipice edge-slide context
Port the first retail precipice-slide slice from named retail/ACE: terrain and BSP walkable hits now preserve polygon vertices, failed step-down edges back-probe to rediscover the walkable polygon, and edge-slide can run precipice/cliff slide instead of only hard-stopping. Adds pseudocode anchors plus regression coverage for terrain polygon context and loaded-terrain boundary edge-slide. Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
parent
1ec40f2a4f
commit
261322b48e
10 changed files with 559 additions and 60 deletions
|
|
@ -4,6 +4,13 @@ using System.Numerics;
|
|||
|
||||
namespace AcDream.Core.Physics;
|
||||
|
||||
internal readonly record struct TerrainWalkableSample(
|
||||
System.Numerics.Plane Plane,
|
||||
Vector3[] Vertices,
|
||||
float WaterDepth,
|
||||
bool IsWater,
|
||||
uint CellId);
|
||||
|
||||
/// <summary>
|
||||
/// Top-level physics resolver that combines <see cref="TerrainSurface"/> and
|
||||
/// <see cref="CellSurface"/> to resolve entity movement with step-height
|
||||
|
|
@ -162,6 +169,51 @@ public sealed class PhysicsEngine
|
|||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sample the outdoor terrain walkable triangle at the given world-space
|
||||
/// XY position. This carries the same plane as <see cref="SampleTerrainPlane"/>
|
||||
/// plus world-space triangle vertices for retail precipice-slide.
|
||||
/// </summary>
|
||||
internal TerrainWalkableSample? SampleTerrainWalkable(float worldX, float worldY)
|
||||
{
|
||||
foreach (var kvp in _landblocks)
|
||||
{
|
||||
var lb = kvp.Value;
|
||||
float localX = worldX - lb.WorldOffsetX;
|
||||
float localY = worldY - lb.WorldOffsetY;
|
||||
if (localX >= 0f && localX < 192f && localY >= 0f && localY < 192f)
|
||||
{
|
||||
var sample = lb.Terrain.SampleSurfacePolygon(localX, localY);
|
||||
var vertices = new Vector3[sample.Vertices.Length];
|
||||
for (int i = 0; i < sample.Vertices.Length; i++)
|
||||
{
|
||||
var v = sample.Vertices[i];
|
||||
vertices[i] = new Vector3(
|
||||
v.X + lb.WorldOffsetX,
|
||||
v.Y + lb.WorldOffsetY,
|
||||
v.Z);
|
||||
}
|
||||
|
||||
var normal = sample.Normal;
|
||||
float d = -Vector3.Dot(normal, vertices[0]);
|
||||
var plane = new System.Numerics.Plane(normal, d);
|
||||
|
||||
float waterDepth = lb.Terrain.SampleWaterDepth(localX, localY);
|
||||
bool isWater = waterDepth >= 0.45f;
|
||||
uint lowCellId = lb.Terrain.ComputeOutdoorCellId(localX, localY);
|
||||
uint fullCellId = (kvp.Key & 0xFFFF0000u) | lowCellId;
|
||||
|
||||
return new TerrainWalkableSample(
|
||||
plane,
|
||||
vertices,
|
||||
waterDepth,
|
||||
isWater,
|
||||
fullCellId);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolve the outdoor cell id that owns a world-space position.
|
||||
/// Indoor ids are preserved because EnvCell ownership still comes from
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue