离散状态和动画转换
Discrete state and animated transitions
我想知道如何以功能方式将绘制游戏与改变状态联系起来。我的意思是游戏逻辑是根据所选动作获取当前状态和 return 新状态的函数。这一切都很好,但根据定义,它意味着状态以离散方式转换。例如,在俄罗斯方块中没有状态,而砖块是半尾向下。因此,如果想要动画化过渡,就会出现如何确定实际发生了什么的问题。让我们将状态视为包含 n 个敌人位置的二维数组。如果最初有两个敌人位于 (10,10) 和 (15,20) 位置,则没有单一的解决方案可以让他们过渡到 (12,13) 和 (16,11)。我们只是不知道哪个是哪个。给定两个状态,我无法确定一个状态是从 (10,10) 移动到 (15,20) 还是移动到 (16,11)。
我想到的第一个解决方案是给每个敌人一个 id。但就我而言,我只对他们的位置感兴趣,这使我的内部状态复杂化,只是为了允许动画转换。
第二种方法 return 不仅是新状态,而且是实际发生的事件列表。然后有了这样的事件,很容易为过渡设置动画。这里的事件类似于 EnemyMoved(oldPosition, newPosition)
。这个解决方案似乎也不是一个优雅的解决方案。域 API 会变得有点荒谬。新状态是此类事件的确切结果,因此 return 将它们放在一起没有多大意义。我考虑过以一种方式进行分离,其中领域逻辑只发出事件,而状态是通过在外部处理此类事件来构建的。但是很难想象如何在函数式编程方法中实现这种行为。我们甚至可以假设状态是同步变化的——不会同时采取两个动作。
我使用 Scala,但我认为这是一个更普遍的问题。如果有任何建议、搜索条件、链接等,我将不胜感激:)
所有解决方案都有效。
现在,有一个矛盾:
I am interested only in their positions
和
one wants to animate the transition
如果 enemy 的属性可以改变,并且它仍然很重要,那么它在 DDD 中就是一个 entity 并且它有一个 id 是非常有意义的。
还有一种类似于您描述的游戏:国际象棋。它有一个 standard notation with a large history,您可能会看到它在必要时使用片段名称和一些消歧(文件、等级或两者)(在某种程度上,它是一个 ID,只有在考虑过去的状态时才有意义);或者在长代数符号中,始终包括起始位置,类似于您的 EnemyMoved(oldPosition, newPosition)
想法。所以你可以做他们做的事——让事件对阅读日志的人更友好。
最后,虽然您的域逻辑可能表示为 (Event, State) => State
的函数,但触发事件的任何内容都可能在将事件传递给 UI 之前简单地将事件与新状态组合在一起。在信息被完全使用之前不丢弃信息没有错,特别是如果 UI 将有效地从两个状态重建事件。如果您想要动画,您的 UI 状态类型必须比您的域的状态类型更丰富,因此将最后一个事件保持在更丰富的状态并没有错。
我想知道如何以功能方式将绘制游戏与改变状态联系起来。我的意思是游戏逻辑是根据所选动作获取当前状态和 return 新状态的函数。这一切都很好,但根据定义,它意味着状态以离散方式转换。例如,在俄罗斯方块中没有状态,而砖块是半尾向下。因此,如果想要动画化过渡,就会出现如何确定实际发生了什么的问题。让我们将状态视为包含 n 个敌人位置的二维数组。如果最初有两个敌人位于 (10,10) 和 (15,20) 位置,则没有单一的解决方案可以让他们过渡到 (12,13) 和 (16,11)。我们只是不知道哪个是哪个。给定两个状态,我无法确定一个状态是从 (10,10) 移动到 (15,20) 还是移动到 (16,11)。
我想到的第一个解决方案是给每个敌人一个 id。但就我而言,我只对他们的位置感兴趣,这使我的内部状态复杂化,只是为了允许动画转换。
第二种方法 return 不仅是新状态,而且是实际发生的事件列表。然后有了这样的事件,很容易为过渡设置动画。这里的事件类似于 EnemyMoved(oldPosition, newPosition)
。这个解决方案似乎也不是一个优雅的解决方案。域 API 会变得有点荒谬。新状态是此类事件的确切结果,因此 return 将它们放在一起没有多大意义。我考虑过以一种方式进行分离,其中领域逻辑只发出事件,而状态是通过在外部处理此类事件来构建的。但是很难想象如何在函数式编程方法中实现这种行为。我们甚至可以假设状态是同步变化的——不会同时采取两个动作。
我使用 Scala,但我认为这是一个更普遍的问题。如果有任何建议、搜索条件、链接等,我将不胜感激:)
所有解决方案都有效。
现在,有一个矛盾:
I am interested only in their positions
和
one wants to animate the transition
如果 enemy 的属性可以改变,并且它仍然很重要,那么它在 DDD 中就是一个 entity 并且它有一个 id 是非常有意义的。
还有一种类似于您描述的游戏:国际象棋。它有一个 standard notation with a large history,您可能会看到它在必要时使用片段名称和一些消歧(文件、等级或两者)(在某种程度上,它是一个 ID,只有在考虑过去的状态时才有意义);或者在长代数符号中,始终包括起始位置,类似于您的 EnemyMoved(oldPosition, newPosition)
想法。所以你可以做他们做的事——让事件对阅读日志的人更友好。
最后,虽然您的域逻辑可能表示为 (Event, State) => State
的函数,但触发事件的任何内容都可能在将事件传递给 UI 之前简单地将事件与新状态组合在一起。在信息被完全使用之前不丢弃信息没有错,特别是如果 UI 将有效地从两个状态重建事件。如果您想要动画,您的 UI 状态类型必须比您的域的状态类型更丰富,因此将最后一个事件保持在更丰富的状态并没有错。