命令模式 · Design Patterns Revisited · 游戏设计模式
首先是命令模式,将所有可能的操作一一列出来,然后把它们区分,取编号,然后就可以将操作描述为数据。
这在生产力软件上可以说是必备的,联网游戏也可以说每一次发数据包都在使用命令模式。
文章后面的实现又不是实际应用,也不够抽象,可以说不值得看,有点废话。
这种模式最广为人知的使用情况。 如果一个命令对象可以做一件事,那么它亦可以撤销这件事。 在一些策略游戏中使用撤销,这样你就可以回滚那些你不喜欢的操作。 它是创造游戏时必不可少的工具。 一个不能撤销误操作导致的错误的编辑器,肯定会让游戏设计师恨你。
策略游戏有了撤销功能真的是很大的提升,不过我玩过的策略游戏没有太多这么做的,更多的是死亡后读档。可能是出于减少玩家抉择和策略深度的原因?毕竟如果你能无限次撤销(而没有死亡的惩罚),那你必然会追求最优解。
还有一个程序方面的问题让它很难实现,如果这个命令在执行的时候有副作用?该如何撤销副作用?例如我执行了一个命令,点燃炸药桶,接着炸药桶爆炸了,它将一堆物体和地形炸变形了。这个时候我选择撤销——如果要实现这个功能,我还要让代码记住爆炸所修改的物体和地形,以便在撤销时恢复它们的状态。我不能只是让消失的炸药桶回来。
对于生产力软件来说,如果你处理的是一段文本、一张图片,或需命令的执行和撤销都很好做(删掉了一段文字,那就把文字再加回来),但游戏的状态太复杂了,很难做到撤销(理论上可以做但消耗程序员脑力)
糟糕的翻译
考虑到在谈论C++,那么函子这个翻译可以说是机翻,functor在C++中是指函数对象,一个有变量(既状态)的函数。但毕竟我是免费看的这篇文章,所以不能批评作者。
这里的观点改变了我的认知,我一直以为命令模式需要我自己模拟函数状态,但在有的语言中,函数本身就可以成为命令。
事件队列 · Decoupling Patterns · 游戏设计模式
除非还呆在一两个没有互联网接入的犄角旮旯,否则你很可能已经听说过“事件序列”了。 如果没有,也许“消息队列”或“事件循环”或“消息泵”可以让你想起些什么。 为了唤醒你的记忆,让我们了解几个此模式的常见应用吧。
啊,拜托,我好不容易想炫耀下我花了两周实现的框架,但在这里看到,原来每个人都听过这个概念了。
但是,好吧,只要能使用电脑,每个人都已经听过它了,windows就是这么设计的,当我连续点击某个软件没反应,几秒后弹出四五个页面,这不显然就是事件队列吗?
我又学到什么是Event-driven programming,事件驱动程序设计,意思是,原来用户命令什么,电脑便全力去处理这件事,但现在不对了,是用户的动作产生事件,然后由程序接收事件,由程序决定什么办。
不是不给你办,是要慢慢办,按计划办,回去等通知。
结合上面的命令模式,就有了卡牌游戏的逻辑处理流程。
又一个糟糕的翻译
A queue stores a series of notifications or requests in first-in, first-out order. Sending a notification enqueues the request and returns. The request processor then processes items from the queue at a later time. Requests can be handled directly or routed to interested parties. This decouples the sender from the receiver both statically and in time.
事件队列在队列中按先入先出的顺序存储一系列通知或请求。 发送通知时,将请求放入队列并返回。 处理请求的系统之后稍晚从队列中获取请求并处理。 这解耦了发送者和接收者,既静态又及时。
根据同一段落at a later time,这个及时并不是一般意思中的【立即;马上】【来得及,赶上需要的时候】,相反它就是字面意义,就是说事件的发送和接收可以不同时,在时间概念上解耦了。
如果按照【立即,马上】来理解,那可以说是刚好相反。
刚好,全局变量引发的连锁反应,对于卡牌来说是个绝妙的灵药,大家都很渴望在卡牌上实现尽可能多的相关性。
这部分讲的不是很好。这个比喻太模糊了。 可以用植物大战僵尸来说,蹦极僵尸和篮球僵尸都以保护伞为目标,但是它们都是延时的,那么蹦极僵尸在几秒后降下,自然不能假设保护伞还在。不能在发送事件时检测状态,要在处理事件时检测状态。但是不管是否延时,蹦极僵尸都要储存它到达的地点,这并不会让它储存更多信息。
至于为什么这部分讲的不好:
1,它是针对延时的事件系统来说的。但有些东西并不用延时。例如怪物死亡,系统不需要等到怪物死亡动画播放结束后才计算获得的经验。
2,不能假设现在的状态反映了事件发生时的世界?
这到底是什么意思?现在状态是什么?反映事件发生时世界?作者举的例子好像一个非常糟糕的游戏框架,所以他完全说不明白。
我从万智牌里得到了灵感,一个操作是一定有一个来源和目标的,然后还会划分打出时储存哪些信息,在执行时再分析哪些信息(例如听起来很废话的:选择一个目标,对它做XXX,如果你以此法做XXX,便做XX)
前面就是事件发送时做的事情,后面是事件被处理时才会发生的事情。
很好的模式,但是在讲述实现细节时,又解释的不是很好。看得很沮丧。
还有十几个设计模式,让我慢慢看下去。
在策略模拟游戏(SLG)里实现撤销行为并非难事。可借助列表这一数据结构来存储每个步骤对应的运行环境变量,并且为避免列表无限制增长,可设定仅保留最近的 10 个操作节点,或者根据游戏回合机制,存储一个回合至三个回合内的操作节点。
具体的操作流程如下:每当玩家触发一次行动指令,系统会立即在列表中插入一条当前步骤的环境变量记录。此时,游戏主环境的变量并不会马上更新,而是在当前操作完整处理完毕后,才将列表中记录的最新状态应用到游戏主环境中。
若只是单纯实现撤销功能,直接从列表中取出上一个记录并恢复相应的环境变量即可。然而,若要让撤销操作呈现出优雅的效果,则需要考虑更多细节。比如,在撤销时添加反向播放的动画效果,以直观展示游戏状态的回溯;同步播放回滚声音,增强听觉反馈,使撤销过程更具沉浸感;同时,还需回滚对话记录,确保聊天信息与游戏状态一致。这样全方位的优化,能让玩家在撤销操作时获得更加流畅和舒适的游戏体验。