代码之家  ›  专栏  ›  技术社区  ›  Cosmik11

EnemyAI沿Y轴反向旋转

  •  -1
  • Cosmik11  · 技术社区  · 8 年前

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

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

    敌人总是有其当前目标的参考。我的想法是,一旦敌人最初发现其目标,它可以保存最近发现的位置,然后获取当前目标位置的增量。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);
            }
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   meowgoesthedog    8 年前

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

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

    这可以检查目标是否位于敌人目标位置的右侧。但它并不适用于所有可能的职位。(在Z轴上翻转坐标的图片-它还能工作吗?)

    正确的方法是使用 2D叉积:

    (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度范围内。但这应该是一种粗糙的方法。