C# 统一字符移动太快

C# 统一字符移动太快,c#,unity3d,unity5,C#,Unity3d,Unity5,我试图为一个敌人写一个AI,这样他每秒钟都会移动到一个新的可用方格。我把他放在瓷砖地图上的一个点上,并附上一个脚本。因为我不想让他在每一帧都尝试选择一个新的方向,所以我做了一些研究,看起来最好的选择是做一个协同程序,这样就不会执行每一帧。我在IEnumerator的update函数中尝试了几个小时的不同方式,打开了各种各样的检查,但到目前为止,我的角色似乎要么像乒乓球一样弹跳,要么静止不动。这是我现在在协同程序中的代码 IEnumerator iMove() { List<stri

我试图为一个敌人写一个AI,这样他每秒钟都会移动到一个新的可用方格。我把他放在瓷砖地图上的一个点上,并附上一个脚本。因为我不想让他在每一帧都尝试选择一个新的方向,所以我做了一些研究,看起来最好的选择是做一个协同程序,这样就不会执行每一帧。我在IEnumerator的update函数中尝试了几个小时的不同方式,打开了各种各样的检查,但到目前为止,我的角色似乎要么像乒乓球一样弹跳,要么静止不动。这是我现在在协同程序中的代码

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);
}
IEnumerator iMove()
{
列表可用=新列表();
可供选择。添加(“北”);
添加(“南方”);
可用。添加(“东”);
添加(“西部”);
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})
{
可用。移除(“北”);
}
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}))
{
可用。移除(“南”);
}
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}))
{
可用。移除(“西部”);
}
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}))
{
可用。移除(“东”);
}
如果可用(计数>0)
{
int random=random.Range(0,(available.Count));
字符串方向=可用[随机];
Log(“正在尝试移动…”+方向);
开关(方向)
{
“北”案:
移动向量y=1f;
moveVector.x=0;
电流y+=1;
打破
“南方”案:
y=-1f;
moveVector.x=0;
电流y-=1;
打破
“东”案:
moveVector.y=0;
moveVector.x=-1f;
电流x+=1;
打破
“西部”案:
moveVector.y=0;
moveVector.x=1f;
电流x-=1;
打破
}
Log(“当前目标:“+currentX+”,“+currentY”);
Push(新的int[]{currentX,currentY});
}
其他的
{
int[]test=myStack.Pop();
currentX=测试[0];
电流Y=试验[1];
}
返回新的WaitForSeconds(1);
transform.position=新矢量3int(currentX,currentY,0);
moveState=moveState.Walk;
anim.SetFloat(“moveX”,movevevector.x);
anim.SetFloat(“moveY”,movevevector.y);
anim.SetBool(“isMoving”,真);
返回新的WaitForSeconds(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);
    }
}
这样,它将等待一秒钟,返回循环的Begining并再次执行

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

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

    StartCoroutine(iMove());
}

最后,请注意,当您销毁游戏对象时,此协同程序将被销毁。你也可以通过调用
StopAllCoroutines()

来停止它。你需要了解一个coroutine是如何工作的:你调用这个函数,本质上是说“做这个,我不在乎它需要多长时间,当它运行时,继续做通常的事情(即
更新()
)。”它不等待它完成,它不在乎是否再次调用coroutine函数(堆栈上只会有多个副本),也不能做任何事情来检查函数是否已完成。这就像生成一个子工作线程,只是它是同步的。我确实理解协同路由,但它似乎不是这样工作的。考虑到协程包含一个等待1秒的命令,该协程运行所需的最短时间为1秒(假设其余代码的加载时间为0),但当我向协程抛出调试时,协程每秒执行多次。如果您是从
Update()
调用它,则是,是的,会的。因为堆栈上有多个副本。好的,这很有意义。那我该怎么解决呢?我尝试从一开始就调用repeating,但它从来没有遇到我放置的任何调试代码…@halfheartd你能提供启动协同程序的代码吗?