使用开关进行简单的 Unity3D 巡逻移动

本文关键字:Unity3D 移动 简单 开关 | 更新日期: 2023-09-27 17:55:08

我正在使用 switch 语句在敌人身上创建两种移动类型:前进和后退。敌人有三个巡逻点。当他开始时,我希望他从第一个巡逻点移动,并在他到达第二个巡逻点(空 3D 游戏对象)时将 1 加到当前点,依此类推。然后我会让他在到达终点时反转方向。

switch (moveType)
        {
        case MoveType.Forward:
            if (transform.position == patrolPoints[currentPoint].position)
            {
                currentPoint ++;
            }
            break;
        case MoveType.Backwards:
            if (transform.position == patrolPoints[patrolPointsLength].position)
            {
                currentPoint --;
            }
            break;
        }

问题是,我找不到一种方法来"触发"两个MoveType。我如何对此进行编码,以便在敌人到达他的最后一个巡逻点时,他切换到 MoveType.Backs?我敢肯定,我正在使这种方式变得比它需要的更难。感谢您的帮助!

使用开关进行简单的 Unity3D 巡逻移动

如果我真的想使用 switch 语句,我会这样做:

    float someSmallValue = 0.5f; // Adjust this as per your needs
    if (Vector3.Distance(transform.position, patrolPoints[currentPoint].position) < someSmallValue)
    {
        switch (moveType)
        {
            case MoveType.Forward:
                currentPoint++;
                if (currentPoint > patrolPoints.Length - 1)
                {
                    currentPoint -= 1;
                    moveType = MoveType.Backwards;
                }
            break;
            case MoveType.Backwards:
                currentPoint--;
                if (currentPoint < 0)
                {
                    currentPoint = 1;
                    moveType = MoveType.Forward;
                }
            break;
        }
    }

我认为将currentPoint重命名为targetPoint将使该代码块的变量名称更加清晰。

编辑:我忘了在向后案例块内递减当前点。更新了我的答案。

我在这里的解决方案增加了一些东西,比如暂停时间。它还确保快速移动的实体不会超过目的地,也不会掉头或其他东西。

// Movement speed normalized. So 1 is instantaneous travel and zero is no movement.
public float movementSpeed = 0.025;
// Let's add a 'pause' time where the unit waits a while at the turning point.
public float waitTime = 1;
// Lets say the list has 5 points.
public List<Vector3> patrolPoints ... 
// We keep track of our starting and ending points. Here we start at zero and move to position 1.
public Vector2 currentLeg = new Vector2(0,1);
// We use a coroutine
IEnumerator Patrol()
{
    // This keeps track of where we are. 0 is at the starting point and 1 is at the destination.
    float progress = 0;
    while(true)
    {
            Vector3 startingPoint = patrolPoints[currentLeg.x];
            Vector3 destination = patrolPoints[currentLeg.y];
            // Please note this won't compile. It's for brevity. You must lerp x,y,z indiviualy in C#.
            transform.position = Mathf.Lerp(startingPoint, destination, progress);
            progress+= movementSpeed;
            // If we are at our destination
            if(progress >=1 )
            {
                // Reset our progress so wa can start over.
                progress = 0;
                // Our current point is now what our destination was before.
                currentLeg.x = currentLeg.y;
                switch(moveType)
                {
                    case MoveType.Forward: 
                    {
                        // If this condition is true then it means we are at the final point (4 in this case). So we invert the movement direction and set the current point to 3.
                        if(currentLeg.y == patrolPoints.Count()-1)
                        {
                            currentLeg.y -= 1;
                            moveType = MoveType.Backwards;
                           // We wait 1 seconds and then do everything again.
                           yield return new WaitForSeconds(waitTime);
                        }
                        else
                            currentLeg.y++;
                    }
                    break;
                    case MoveType.Backward:
                    {
                        // If this condition is true then it means we are at the starting point (0). So we invert the movement direction and set the current point to 1.
                        if(currentLeg.y == 0)
                        {
                            currentLeg.y += 1;
                            moveType = MoveType.Forward;
                            // We wait 1 seconds and then do everything again.
                            yield return new WaitForSeconds(waitTime);
                        }
                        else
                            currentLeg.y--;
                    }
                    break;
                }
            }
    }
}

为了快速修复,杰森的答案会更好。但是,如果设备移动得太快,它可能会失败,或者如果设备移动太慢,它可能会过早停止。

编辑:等待时间在错误的地方。

所以你想使用开关进行巡逻,因为一次只能选择 1 个枚举?

为什么不使用public Transform target;变量并让您的 AI 始终遵循该变量中的内容?然后只需创建一个空的游戏对象并将其粘贴到该变量中,无论它走到哪里,他都会跟随它。他不会局限于"前进"和"后退",当你想回收将"左"移动到"右"的AI的代码时,你不必重新编码或感到困惑。

这将加快执行速度,清理代码,摆脱大量代码行,并且您仍然可以使用switch语句,因为这实际上将使您的代码具有更多的动态功能,例如:

public enum ActionType
{
    Patrol,
    Veer,
    Stop
}

假设他正在巡逻,在目标的一半他发现了一个敌人,ActionType curAction;可以设置为ActionType.Veer,现在他正在偏离巡逻线攻击敌人,在你可以将其设置回ActionType.Patrol之后,他继续向目标前进。

因此,对于巡逻,您可以设置一个public List<Vector3> wayPoints;,只需在其中添加一堆Vector3即可。当他到达目标时,他可以停下来一两秒钟,然后让空的游戏对象目标跳到列表中的下一个 vector3。