0

我正在实施一个用于运行游戏 AI 脚本的光纤系统,但遇到了一个小问题。

我在脚本中使用 yield return x 来表示等待 x 帧。我想封装计算 x 帧的逻辑,因为其他事件可以修改要等待的帧数。我理想的解决方案如下:

public Boolean removeScript = false;

public IEnumerable update()
{
    while(true)
    {
        shootAtPlayer()
        wait(30)
    }
}

private IEnumerable wait(int x)
{
    yield return removeScript ? -1 : x;
}

wait() 要么指示产生返回 30,要么在不再需要脚本时返回 -1。迭代器将通过删除脚本来处理 -1 返回。如果 x > 0,迭代器将每帧递减返回值直到 0,然后再次调用 update()。

但是,这不起作用,因为 wait() 的收益返回当然不会传播到更新方法。这会导致代码重复、模块性变差和代码可读性降低:

public IEnumerable update()
{
    while(true)
    {
        shootAtPlayer()
        yield return removeScript ? -1 : x;
    }
}

我想知道是否有更好的方法来构建它?还是我缺少在这种情况下有用的语言功能?

4

1 回答 1

1

在这种特定情况下,解决方案相对简单:Wait()只返回整数:

public IEnumerable Update()
{
    while (true)
    {
        ShootAtPlayer();
        yield return Wait(30);
    }
}

private int Wait(int x)
{
    return removeScript ? -1 : x;
}

在更复杂的情况下,您可以使用foreach,但这会使语法更加冗长:

public IEnumerable Update()
{
    while (true)
    {
        ShootAtPlayer();

        foreach (var x in Wait(30))
            yield return x;
    }
}

private IEnumerable Wait(int x)
{
    yield return removeScript ? -1 : x;
}

如您所见,您可以(ab)使用yield return来实现光纤,但yield return从来没有为此而设计,所以它不会那么好用。

为这种异步延续所做的是新的async- await。这样,您的代码可能看起来像这样:

public async Task Update()
{
    while (true)
    {
        ShootAtPlayer();
        await Wait(30);
    }
}

private async Task Wait(int x)
{
    await fiber.Wait(removeScript ? -1 : x);
}

最后一点,我认为您使用的方式removeScript不是一个好主意。脚本的结束应该由Update()实际完成的方法来表示(枚举没有更多的项目,或者Task完成),而不是返回一个神奇的值。

于 2013-06-04T12:29:22.063 回答