【问题标题】:Unity Character Moving Too QuicklyUnity 角色移动太快
【发布时间】:2018-02-07 16:18:10
【问题描述】:

我正在尝试为敌人编写一个 AI,以便他每秒移动到一个新的可用方格。我将他放置在地图上的某个点上,并附有脚本。因为我不希望他在每一帧都尝试选择一个新方向,所以我做了一些研究,似乎最好的选择是做一个协程,这样它就不会执行每一帧。我已经尝试了几个小时在更新功能中编写这种不同的方式,在 IEnumerator 中,打开了各种检查,但到目前为止,我的角色似乎总是像乒乓球一样弹跳或静止不动。这是我现在在协程中的代码。

IEnumerator iMove()
{
    List<string> available = new List<string>();

    available.Add("North");
    available.Add("South");
    available.Add("East");
    available.Add("West");

    if (tilemap.GetTile(new Vector3Int(currentX, currentY + 1, 0)) == null || tilemap.GetTile(new Vector3Int(currentX, currentY + 1, 0)).name != floor || myStack.Contains(new int[] { currentX, currentY + 1 }))
    {
        available.Remove("North");
    }
    if (tilemap.GetTile(new Vector3Int(currentX, currentY - 1, 0)) == null || tilemap.GetTile(new Vector3Int(currentX, currentY - 1, 0)).name != floor || myStack.Contains(new int[] { currentX, currentY - 1 }))
    {
        available.Remove("South");
    }
    if (tilemap.GetTile(new Vector3Int(currentX - 1, currentY, 0)) == null || tilemap.GetTile(new Vector3Int(currentX - 1, currentY, 0)).name != floor || myStack.Contains(new int[] { currentX - 1, currentY }))
    {
        available.Remove("West");
    }
    if (tilemap.GetTile(new Vector3Int(currentX + 1, currentY, 0)) == null || tilemap.GetTile(new Vector3Int(currentX + 1, currentY, 0)).name != floor || myStack.Contains(new int[] { currentX + 1, currentY }))
    {
        available.Remove("East");
    }

    if (available.Count > 0)
    {
        int random = Random.Range(0, (available.Count));
        string direction = available[random];
        Debug.Log("attempting to move..." + direction);
        switch (direction)
        {
            case "North":
                moveVector.y = 1f;
                moveVector.x = 0;
                currentY += 1;
                break;
            case "South":
                moveVector.y = -1f;
                moveVector.x = 0;
                currentY -= 1;
                break;
            case "East":
                moveVector.y = 0;
                moveVector.x = -1f;
                currentX += 1;
                break;
            case "West":
                moveVector.y = 0;
                moveVector.x = 1f;
                currentX -= 1;
                break;
        }
        Debug.Log("current goal:" + currentX + "," + currentY);
        myStack.Push(new int[] { currentX, currentY });
    }
    else
    {
        int[] test = myStack.Pop();

        currentX = test[0];
        currentY = test[1];
    }

    yield return new WaitForSeconds(1);
    transform.position = new Vector3Int(currentX, currentY, 0);
    moveState = MoveState.Walk;
    anim.SetFloat("moveX", moveVector.x);
    anim.SetFloat("moveY", moveVector.y);
    anim.SetBool("isMoving", true);
    yield return new WaitForSeconds(1);
}

【问题讨论】:

  • 您需要了解协程是如何工作的:您调用该函数并基本上说“做这个,我不在乎需要多长时间,在它运行时,继续做通常的事情(即@ 987654322@)。”它不等待它完成,它不关心你是否第二次调用协程函数(堆栈上只会有多个副本),你不能做任何事情来检查是否功能已完成。它就像产生一个子工作线程,除了它是同步的。
  • 我确实了解协程,但它似乎并没有那样工作。考虑到协程包含一个等待 1 秒的命令,这个协程运行所需的最低限度是 1 秒(假设其余代码的加载时间为 0),但是当我抛出一个协程时,协程每秒执行 MULTIPLE 次调试到协程中。
  • 如果您从Update() 调用它,那么是的,是的。因为栈上有多个副本。
  • 好的,有道理。那么我该如何解决呢?我尝试从头开始调用重复,它从来没有碰到我放置的任何调试代码......
  • @halfheartd 能否提供启动协程的代码?

标签: c# unity3d unity5


【解决方案1】:

这取决于你如何启动协程。如果你开始在Update,当然它会在每一帧开始,你会有很多协程同时运行。

尝试只启动一次:

public void Start()
{
    StartCoroutine(iMove());
}

现在,它将执行一次,因此您将看到您的播放器移动一次。如果你想重复它,你可以:

1) 在协程中添加一个while循环

IEnumerator iMove()
{
    while(true) // or a boolean condition that you can set yourself
    {
        // Your code
        // ...
        yield return new WaitForSeconds(1f);
    }
}

这样它会等待一秒钟,回到循环的开头并再次执行

另一种可能是协程完成后再次启动:

IEnumerator iMove()
{
    // Your code
    // ...
    yield return new WaitForSeconds(1f);

    StartCoroutine(iMove());
}

最后,注意这个协程会在你销毁游戏对象的时候被销毁。你也可以拨打StopAllCoroutines()停止它

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多