我读过“Purely Functional Retrogames”系列
http://prog21.dadgum.com/23.html
它讨论了构建(半)纯游戏世界更新循环的一些有趣技巧。
但是,我有以下方面的评论,我似乎无法理解:
假设你有一个系统,每个敌人,每个玩家都是独立的演员,或者是单独的纯粹功能。
假设他们都获得了一个“WorldState”作为输入,并输出一个New WorldState(或者,如果您正在考虑演员术语,则将新WorldState发送给下一个actor,以例如“Game Render”演员结束)。
然后,有两种方法可以解决这个问题:
要么从一个演员开始,(f.i.播放器),要么给他“当前世界”。 然后,你将新世界,下一个敌人,等等,直到所有演员都改变了世界。然后,最后一个世界是你可以提供给渲染循环的新世界。 (或者,如果你按照上面的文章,你最终会得到一个世界上发生的事件清单,可以加工)。
第二种方式,就是同时给所有演员当前的WorldState。它们产生任何可能发生冲突的变化(例如,两个敌人和玩家可以在相同的动画帧中获取硬币) - >通过处理事件来解决这些冲突取决于游戏系统。通过处理所有事件,Game actor创建新世界,用于下一个更新框架。
我有一种感觉,我只是面对完全相同的“竞争条件”问题,我希望通过使用具有不可变数据的纯函数来避免这种问题。
这里有什么建议吗?
答案 0 :(得分:5)
我没有读过这篇文章,但是用硬币的例子你正在创建一种全局变量:你给所有演员一个世界状态的副本,你想每个演员都会评估游戏,拿走决定并期望他们的行动能够成功,无论解决冲突的最后阶段如何。我不会把这称为竞争条件而是盲目条件",是的,这不起作用。
我想你来到这个解决方案是为了允许并行性,在解决方案1中不可用。在我看来,问题在于责任。
硬币必须属于应用程序中的任何actor(充当资源管理器的服务器)。这个演员是唯一负责决定硬币会发生什么的人。
所有请求(有抓取东西,抓住它,丢弃东西......)应该发送给这个演员(每个单元一个演员,或者每个地图,等级或任何对游戏有意义的分裂)。 / p>
您管理它的方式取决于您:在接收订单中提供所有请求,缓冲它们直到同步消息到来并做出随机决策或优先级决定......无论如何,服务器将能够回复所有成功或失败的参与者,没有任何竞争条件的风险,因为服务器进程在一个核心上运行(至少在erlang中)并且一次进行一条消息。
答案 1 :(得分:2)
除了Pascal答案之外,您还可以通过将(我假设巨大的地图)拆分为较小的块来解决并行化,这些较小的块依赖于其邻居的最后状态(或其一部分,如边缘)。这允许您在许多节点之间分发此游戏。