【问题标题】:Discrete state and animated transitions离散状态和动画转换
【发布时间】:2021-07-01 10:56:54
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: scala functional-programming game-development


    【解决方案1】:

    所有解决方案都有效。

    现在,有一个矛盾:

    我只对他们的职位感兴趣

    想要动画过渡

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

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

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

    【讨论】:

    • 这是一个很好的答案,你是完全正确的。谢谢你的澄清。作为我的心智模型,我使用了 Candy Crush Saga 游戏。这就是为什么我假设每个紫罗兰色砖都等于任何其他的,而我需要保持的状态是棋盘上的特定位置被该颜色占据。但是考虑到我意识到的国际象棋例子是一种错觉,他们是平等的:D
    猜你喜欢
    • 2012-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-30
    • 2017-11-14
    • 1970-01-01
    • 1970-01-01
    • 2013-01-09
    相关资源
    最近更新 更多