背景

我的多人游戏Lights Out基于2D网格。实体只能在一个网格方块中。这种规则评估非常简单和易于理解。但是,它并没有真正让人觉得很好玩(如果你玩过PuzzleScript游戏中的任何一个,你就知道了)。同时,游戏中越多的内容,游戏规则就越复杂和任意。我因此引入了Movement Transaction System来解决这个问题。这包括两个方面:

  • 服务器端的游戏代码处理交易。这将所有移动代码(包括规则评估)整合到一个系统中。
  • 客户端的可视化与预测代码处理移动的可视插值(在交易由服务器管理时引入一些游戏感受),基于服务器的交易。

交易

一个交易包括移动delta、受影响的实体列表以及一些标志。一个交易经过以下几个阶段:

  • Queued: 游戏代码要求实体移动
  • Issued: 客户端的可视插值已经开始,但实体尚未从游戏角度移动
  • Committed: 实体现在已经移动到新的方块,可视插值正在完成
  • Aborted: 交易无法提交,因为它将违反游戏规则。可视插值被反转。

可视插值

当服务器端发出一个交易时,服务器告诉客户端开始一个基于交易的可视插值。这包括所需插值持续时间以及一些标志(如是否使用加速或线性插值)。客户端然后每帧更新可视插值,直到交易被取消或目标位置被达到。

简化游戏代码

这个新系统使得游戏代码变得更加简单。现在我可以轻松地查询一个实体是否有活跃的交易,以确定可视插值是否仍在进行。这使得在世界中实现顺畅的连续移动变得更加容易(例如,对于线性速度移动的火球)。这也保证了实体的可视位置总是接近其游戏(物理)位置,以避免玩家对规则评估感到困惑。最后,游戏规则现在被实现在一个名为validate_transaction的单个函数中,而不是像之前那样分散在所有实体中。

总结

交易系统使得游戏代码变得更加简单和容易理解,同时也提高了游戏感受和可靠性。你可以在https://lightsout.afterthought.games/blog/2026-07-26-19-00找到完整的博客文章,包括更多详细信息和示例代码。