【问题标题】:How should I handle the communication between AI threads and the main game loop?我应该如何处理 AI 线程和主游戏循环之间的通信?
【发布时间】:2011-12-09 17:05:25
【问题描述】:

我正在使用 Java(在 Android 框架中)开发一款回合制策略游戏。按照开始 Android 游戏中的结构,我有一个渲染线程和一个 UI 线程。渲染线程反复更新世界状态,然后重绘世界。当用户与屏幕交互时,GUI 向世界发送动作(命令模式)。现在我正在添加 AI 玩家,这是我的计划:

每个 AI 玩家都有一个在单独线程上运行的 AI。

当世界在 AI 回合中更新时,它会检查是否有待处理的动作。如果是这样,它会执行它。然后它会询问 AI 玩家的下一步行动。

AI 播放器会将动作请求发送到 AI 线程,然后返回。

最终,人工智能会提出一个动作,并将其发布回世界,世界将在下一次更新中看到它。

两个问题:

1) 这个设计听起来不错?

2) 我如何处理与 AI 线程之间的通信?如果我有 AI 线程调用 world.queueAction(action),这似乎可以工作,但如果渲染线程调用 ai.chooseAction(world),它将在渲染线程上运行选择操作,这不是我想要的.

【问题讨论】:

  • 你没有在渲染线程中做世界逻辑,是吗?

标签: java android multithreading artificial-intelligence


【解决方案1】:

我会为 AI 提供一个 ExecutorService,并为您希望它执行的事情添加任务。对于 UI,您可以拥有一系列已更改且可能需要重新绘制的内容。我很想对所有 AI 使用单个线程,直到您知道这会有所帮助。无论如何,大多数 Android 设备只有 1-2 个 CPU。

【讨论】:

  • 好的,所以 AI 类将实现 Runnable,它的 run() 方法将根据当前关卡状态计算下一步移动,然后将新的动作排队到世界。 AIPlayer 会有一个静态的 ExecutorService。当在 AIPlayer 对象上调用 chooseAction() 时,它将使用当前关卡状态更新其 AI 实例,然后告诉执行器服务运行其 AI 实例。
【解决方案2】:

您确定系统能够处理大量线程吗?请记住,运行线程的“最佳”数量通常是n + 1,其中n 是系统拥有的内核 数量。如果这是在手机上运行,​​那么可用的会更少,但除非你运行超过 10 个,否则可能没问题...

对于游戏和 AI 之间的联系,考虑(人类)玩家和 AI 之间的区别可能会有所帮助:只有一个重要区别 - 一个是计算机,另一个不是。最好将 AI 采取的行动提交到与人类玩家完全相同的队列(或通过相同的通用机制)(因此,请致电 world.queueAction(action);)。它还简化了 AI 和人类玩家之间的交换,因为您的世界更新代码不需要知道其中的区别......

我假设您已经有某种事件来通知玩家/在轮到人类玩家时更新屏幕。对 AI 线程执行完全相同的操作 - 让它侦听适当的“轮到你了”事件,使其完成(此迭代)计算并在队列中放置一个动作。请注意,这需要从“世界更新”线程中完成;渲染线程应该只关心将输出渲染到屏幕上(并且只关心玩家输入)。

【讨论】:

    【解决方案3】:

    如果我理解正确:

    • 您有一个渲染线程。据推测,这会以显示帧速率运行。
    • 您有一个“世界逻辑”线程。这从一些可预测的计时器运行。
      • 您在一个线程中有一般物理、玩家输入或其他操作;
      • 每个 AI 角色都有一个单独的线程

    您似乎可以安全地以Future 的形式运行每个 AI 逻辑线程,并在每一帧上执行“世界”线程正在执行的任何其他操作后一起获取它们的结果。

    【讨论】:

    • 实际上是这样的:Android UI 线程(注册用户触摸和其他事件),Render 线程(绘制屏幕并更新世界逻辑,以帧速率运行)。所以世界更新没有定期的“时钟滴答”。也许应该有?
    • 假设那是一个离屏渲染缓冲区还是什么?不是所有的 UI 更新都必须在 Android 上的一个线程中进行吗? (他们在 1.5 中做到了,但我已经过时了,我知道……)
    • 它有一个循环,执行世界逻辑更新,将世界渲染到缓冲区中,然后锁定画布,渲染缓冲区,解锁画布,然后返回顶部。
    • 有趣,不知道你现在能做到。尽管如此,我还是害怕将世界逻辑与渲染联系起来。我建议将世界逻辑的计时器和渲染管道尽可能分开,这样就不会导致显示速度变慢。人物走得更慢。而且,正如 X-Zero 指出的那样,您不太可能拥有多个 CPU,因此使用许多单独的线程可能会过于复杂。