C# Enemyi在Y轴上以相反方向旋转

C# Enemyi在Y轴上以相反方向旋转,c#,unity3d,collision-detection,game-physics,C#,Unity3d,Collision Detection,Game Physics,当战斗旗帜熄灭,玩家进入敌人的战斗区域后,我想在玩家移动时跟踪它,确保敌人的Z轴始终指向玩家 当玩家进入战区时,敌人会自动将玩家标记为其目标,但在首次发起战斗时,Z轴可能不会指向敌人的目标。我决定在战旗熄灭时从敌人的Z轴发射一束射线,并旋转敌人,直到射线与玩家相交,从而告诉我敌人的Z轴已正确排列 敌人总是有一个指向其当前目标的参考。我的想法是,一旦敌人最初发现其目标,它可以保存最近发现的位置,然后获取当前targetPosition.x和最后发现的位置.x的增量,如果增量为正,则向右旋转,如果增

当战斗旗帜熄灭,玩家进入敌人的战斗区域后,我想在玩家移动时跟踪它,确保敌人的Z轴始终指向玩家

当玩家进入战区时,敌人会自动将玩家标记为其目标,但在首次发起战斗时,Z轴可能不会指向敌人的目标。我决定在战旗熄灭时从敌人的Z轴发射一束射线,并旋转敌人,直到射线与玩家相交,从而告诉我敌人的Z轴已正确排列

敌人总是有一个指向其当前目标的参考。我的想法是,一旦敌人最初发现其目标,它可以保存最近发现的位置,然后获取当前targetPosition.x和最后发现的位置.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轴上翻转坐标的图片-它还能工作吗?)

正确的方法是使用二维叉积:

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

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

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

对此还有其他改进,例如,使敌人精确瞄准目标,而不是在5度范围内瞄准。但这应该是一个粗糙的方法

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);