forked from mirror/DotRecast
94 lines
2.9 KiB
C#
94 lines
2.9 KiB
C#
using System;
|
|
using DotRecast.Core;
|
|
using DotRecast.Recast;
|
|
using static DotRecast.Core.RcMath;
|
|
|
|
namespace DotRecast.Detour.Extras.Jumplink
|
|
{
|
|
class TrajectorySampler
|
|
{
|
|
public void Sample(JumpLinkBuilderConfig acfg, Heightfield heightfield, EdgeSampler es)
|
|
{
|
|
int nsamples = es.start.gsamples.Length;
|
|
for (int i = 0; i < nsamples; ++i)
|
|
{
|
|
GroundSample ssmp = es.start.gsamples[i];
|
|
foreach (GroundSegment end in es.end)
|
|
{
|
|
GroundSample esmp = end.gsamples[i];
|
|
if (!ssmp.validHeight || !esmp.validHeight)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!SampleTrajectory(acfg, heightfield, ssmp.p, esmp.p, es.trajectory))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ssmp.validTrajectory = true;
|
|
esmp.validTrajectory = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool SampleTrajectory(JumpLinkBuilderConfig acfg, Heightfield solid, Vector3f pa, Vector3f pb, Trajectory tra)
|
|
{
|
|
float cs = Math.Min(acfg.cellSize, acfg.cellHeight);
|
|
float d = VDist2D(pa, pb) + Math.Abs(pa.y - pb.y);
|
|
int nsamples = Math.Max(2, (int)Math.Ceiling(d / cs));
|
|
for (int i = 0; i < nsamples; ++i)
|
|
{
|
|
float u = (float)i / (float)(nsamples - 1);
|
|
Vector3f p = tra.Apply(pa, pb, u);
|
|
if (CheckHeightfieldCollision(solid, p.x, p.y + acfg.groundTolerance, p.y + acfg.agentHeight, p.z))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool CheckHeightfieldCollision(Heightfield solid, float x, float ymin, float ymax, float z)
|
|
{
|
|
int w = solid.width;
|
|
int h = solid.height;
|
|
float cs = solid.cs;
|
|
float ch = solid.ch;
|
|
Vector3f orig = solid.bmin;
|
|
int ix = (int)Math.Floor((x - orig.x) / cs);
|
|
int iz = (int)Math.Floor((z - orig.z) / cs);
|
|
|
|
if (ix < 0 || iz < 0 || ix > w || iz > h)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Span s = solid.spans[ix + iz * w];
|
|
if (s == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
while (s != null)
|
|
{
|
|
float symin = orig.y + s.smin * ch;
|
|
float symax = orig.y + s.smax * ch;
|
|
if (OverlapRange(ymin, ymax, symin, symax))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
s = s.next;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private bool OverlapRange(float amin, float amax, float bmin, float bmax)
|
|
{
|
|
return (amin > bmax || amax < bmin) ? false : true;
|
|
}
|
|
}
|
|
} |