EnemyAI 在 Y 轴上以相反方向旋转

EnemyAI rotating on Y-axis in opposite direction

在战旗消失并且玩家进入敌人的战区后,我想在玩家移动时跟踪玩家并确保敌人的 Z 轴始终指向玩家。

当玩家进入战斗区域后,敌人会自动将玩家标记为目标,但有可能在战斗刚开始时Z轴未指向敌人的目标。我决定在战旗熄灭时从敌人的 Z 轴投射一条射线,然后旋转敌人直到射线和玩家相交,这告诉我敌人的 Z 轴已正确对齐。

敌人总是有一个指向其当前目标的引用。我的想法是,一旦敌人最初发现了它的目标,它就可以保存最近发现的位置,然后取 CurrentTargetPosition.x 和 LastSpottingPosition.x 的增量,如果增量为正,则向右旋转,如果增量为负向左旋转。

问题:我的数学或逻辑一定有缺陷,因为虽然它有时有效,但有时敌人会随机向相反方向旋转,光线投射基本上会走很长的路来击中玩家而不是预期的最短路线。下面的代码。

//create ray from enemy position orgin and point it on the Z-Axis
    Ray ray = new Ray(CurrentEnemyTransform.position, CurrentEnemyTransform.forward);
    RaycastHit hit;

    if (Physics.Raycast(ray, out hit, 50f))
    {
        Debug.DrawLine(ray.origin, hit.point);

        //ray hits current enemy target
        if (hit.transform == CurrentTargetTransform)
        {
            //check if enemy has seen its target before while in this battle
            //or is it the first time
            if (enemy.hasTargetLastPosition)
                //replace old last seen position with most recent spotting
                enemy.ReplaceTargetLastPosition(hit.transform.position);
            //or add the first spotting of target while in this battle
            else enemy.AddTargetLastPosition(hit.transform.position);
        }
        //ray is not intersectiing with the enemy's current target so rotate to look for it
        if (hit.transform != CurrentTargetTransform)
        {
            //check if enemy has seen its target once before in battle
            if (enemy.hasTargetLastPosition)
            {
                //since last spotting has my target moved more to the left or right?
                if (enemy.targetLastPosition.value.x > CurrentTargetTransform.position.x)
                {
                    //rotate right
                    CurrentEnemyTransform.Rotate(-Vector3.up, 5f, Space.Self);
                }
                        //rotate left
                else CurrentEnemyTransform.Rotate(Vector3.up, 5f, Space.Self);
            }
            //never seen target yet during this battle so default rotation to right till you found it
            else CurrentEnemyTransform.Rotate(-Vector3.up, 5f, Space.Self);
        }

一个明显的问题是这一行:

if (enemy.targetLastPosition.value.x > CurrentTargetTransform.position.x)

这应该会检查目标是否在敌人瞄准位置的右侧。但它并不适用于所有可能的职位。 (图片翻转 Z-axis 中的坐标 - 那么它仍然有效吗?)

正确的方法是使用 2D cross-product:

(Ax, Az) x (Bx, Bz) = Ax * Bz - Az * Bx

如果矢量 A 相对于 B 顺时针旋转,则为正,反之亦然。

(此外,我们需要检查相对于敌人的 相对 位置,而不是他们的世界位置;要做到这一点,只需减去 CurrentEnemyTransform.position

private static bool isOnRight(Vector3 a, Vector3 b)
{
    return a.x * b.z - a.z * b.x > 0.0f;
}

//...

// is last known position on the right of the actual position?
if (isOnRight(enemy.targetLastPosition - CurrentEnemyTransform.position,
              CurrentTargetTransform.position - CurrentEnemyTransform.position))
{
    // rotate *left*, not right
    CurrentEnemyTransform.Rotate(Vector3.up, -5f, Space.Self);
}
else CurrentEnemyTransform.Rotate(Vector3.up, 5f, Space.Self);

还有其他可以对此进行的改进,例如让敌人 准确地 瞄准目标,而不是在 5 度范围内这样做。但这应该是一种粗略的方法。