离散状态和动画过渡

时间:2021-04-05 15:25:36

标签: scala functional-programming game-development

我想知道如何以功能方式将游戏与不断变化的状态连接在一起。我的意思是游戏逻辑是根据选择的动作获取当前状态并返回新状态的函数。这一切都很好,但它的定义意味着状态以离散方式转换。例如,在俄罗斯方块中没有状态,而砖块是半尾向下。因此,如果想要为过渡设置动画,那么如何确定实际发生的情况是一个问题。让我们将状态视为包含 n 个敌人位置的二维数组。如果位置 (10,10) 和 (15,20) 上最初有两个敌人,那么他们如何过渡到 (12,13)​​ 和 (16,11) 没有单一的解决方案。我们只是不知道哪个是哪个。给定两个状态,我无法确定一个从 (10,10) 移动到 (15,20) 还是移动到 (16,11)。

我想到的第一个解决方案是给每个敌人一个 id。但就我而言,我只对他们的位置感兴趣,这让我的内部状态变得复杂,只是为了允许动画过渡。

第二种方法是不仅返回新状态,而且还返回实际发生的事件列表。然后有这样的事件很容易动画过渡。此处的事件类似于 EnemyMoved(oldPosition, newPosition)。这个解决方案似乎也不是一个优雅的解决方案。域 API 会变得有点荒谬。新状态是此类事件的确切结果,因此将它们组合在一起没有多大意义。我想过以一种方式分离,其中域逻辑只发出事件,状态是通过在外部处理此类事件来构建的。但是很难想象如何在函数式编程方法中实现这种行为。我们甚至可以假设状态是同步变化的——不会同时采取两个动作。

我使用 Scala,但我认为这是更一般的问题。我将不胜感激任何建议、搜索条件、链接等:)

1 个答案:

答案 0 :(得分:1)

所有解决方案都有效。

现在,两者之间存在矛盾:

<块引用>

我只对他们的职位感兴趣

<块引用>

想要动画过渡

如果敌人的属性可以改变,而且它之前的状态仍然很重要,那就是 DDD 中的 entity 并且它有一个 id 是非常有意义的。

还有一种类似于您描述的游戏:国际象棋。它有一个 standard notation with a large history,你可能会看到它在必要时使用了片段名称和一些消歧(文件、等级或两者)(在某种程度上,它是一个 ID,但只有在与过去的状态一起使用时才有意义);或在长代数符号中,始终包括起始位置,类似于您的 EnemyMoved(oldPosition, newPosition) 想法。所以你可以做他们所做的 - 让事件对阅读日志的人更友好。

最后,虽然您的域逻辑可能表示为 (Event, State) => State 的函数,但任何触发事件的因素都可能只是简单地将事件与新状态组合在一起,然后再将其传递给 UI。在信息被完全使用之前不丢弃信息没有错,特别是如果 UI 将有效地从两个状态重建事件。如果您想要动画,您的 UI 状态类型必须比您的域中的更丰富,因此将最后一个事件保持在该更丰富的状态并没有错。