这是我在大约20分钟内完成的事情。我们采用从步行者到目标的方向,在该方向的一定角度范围内选择一个方向(随着步行者接近其目标,该方向的数量会减少)。该算法还考虑了到目标的距离,因此它不会走过目标。长话短说,它基本上会在左右随机晃动少量,然后随着距离的临近而回到目标。
为了测试该算法,我将助步器放在(10,0,10),将目标放在(0,0,0)。该算法第一次运行时,随机选择了步行者要行走的位置(3.73f,0,6.71f)。步行者到达该位置后,选择(2.11f,0,3.23f),然后选择(0.96f,0,1.68f),然后(0.50f,0,0.79f),然后因为它在目标范围内而直接走到目标最小公差距离。
从鸟瞰图中绘制出的路径看起来像下图中的点,从“ W”(行人)开始,到“ T”(目标)结束。如果您想要更自然的运动,则可以提前计算一些点,然后创建一个样条,为您提供更多点,您可以让步行者跟随。我已经估算出该路径成为样条线后的样子,并且由图像中的线表示。
这是示例代码:
Vector3 WalkerPosition = new Vector3(10, 0, 10);
Vector3 TargetPosition = Vector3.Zero;
public Game1()
{
// Each time you reach the next walk-to position, call this again.
// Eventually you'll reach your target, assuming the target isn't moving away
// from the walker faster than the walker can reach them.
Vector3 NextWalkToPosition = PickRandomTarget();
}
public Vector3 PickRandomTarget()
{
// For this code sample we'll assume that our two targets are on
// the same horizontal plane, for simplicity.
Vector3 directionToTarget = ( TargetPosition - WalkerPosition );
float distance = directionToTarget.Length();
directionToTarget.Normalize();
float distanceThisIteration = distance * 0.5f;
// We should never walk too little or too far, to make this more realistic
// you could randomize the walking distance each iteration a bit.
distanceThisIteration = MathHelper.Clamp(distanceThisIteration, 1.0f, 10.0f);
// We're within minimum distance to the target, so just go straight to them
if (distanceThisIteration > distance)
{
return TargetPosition;
}
directionToTarget *= distanceThisIteration; // Walk roughly halfway to the target
// Now we pick a new walking direction within an FOV that gets smaller as
// we get closer to the target. We clamp the FOV between 0 and 90 degrees (45 degrees in either direction).
const float walkerAggroRadius = 30.0f; // Walker aggros when within 30 units of target
// Any distance outside of 30 we'll just treat as 30.
float distanceMod = MathHelper.Clamp(distance, 0.0f, walkerAggroRadius);
// We need a percentage value representing the current distance between the min 0, and max, 30
float percentageAlongDistance = distanceMod / walkerAggroRadius;
// We want FOV from center, so we cut the final FOV result in half
float maxFOVAtThisDistance = MathHelper.Lerp(0.0f, MathHelper.PiOver2, percentageAlongDistance) * 0.5f;
// Now we pick a random FOV from center within our maxFOV based on how far we are
// from the target
Random rand = new Random(System.DateTime.Now.Second);
float randFOV = (float)(rand.NextDouble() * maxFOVAtThisDistance);
// Right now our FOV value is an FOV from a vector pointing directly at our target, we now
// need to randomly choose if we're going to aim to the left or right of the target. We'll
// treat a result of 0 as left, and 1 as right
int randDirection = rand.Next(2);
if (randDirection == 0) // Left
{
// Rotate our direction vector left by randFOV radians
return WalkerPosition + RotateAroundPoint(directionToTarget, Vector3.Zero, Vector3.UnitY, -randFOV);
}
else // Right
{
return WalkerPosition + RotateAroundPoint(directionToTarget, Vector3.Zero, Vector3.UnitY, randFOV);
}
}
// Generic helper function to rotate a vector by a specific amount of degrees
public Vector3 RotateAroundPoint( Vector3 point, Vector3 originPoint, Vector3 rotationAxis, float radiansToRotate )
{
Vector3 diffVect = point - originPoint;
Vector3 rotatedVect = Vector3.Transform(diffVect, Matrix.CreateFromAxisAngle(rotationAxis, radiansToRotate));
rotatedVect += originPoint;
return rotatedVect;
}
根据您的特定游戏,您可以调整距离,视场,随机性和运行频率,直到满足您的需求为止。我确信算法可以进行一些清理和优化,我并没有花太多时间,我只是想让它易于阅读。