《The Elements of Computing Systems》 这本计算机教材分为十二章,带领读者从最基础的逻辑门(Nand gate)开始,逐步搭建出能够运行俄罗斯方块(Tetris)的操作系统,所以又被称为 Nand2Tetris。列举几个相关的链接:
我建议先看一遍视频,然后读书、做笔记、写课后题。做笔记有两个目的。第一,梳理知识点之间的逻辑关系:包括不同章节的,以及每个章节内部各个节点的联系。第二,在笔记中写下关键词,要求几周后看到关键词时,依然能回忆起或者快速找到书中对应的内容。详见图 2。
我已经做完前四章习题。ALU、PC(Program Counter)和写汇编做乘法有点麻烦,其余题目只要理解课本知识、读懂题意,做起来都挺简单的。最后特别感谢讲授公开课的两位老师:万磁王爷爷和胡子叔叔。他们讲得很认真、很清楚,耐心鼓励初学者迈出信仰之跃,像草薙素子那样潜入计算机之海,然后浮出水面,看见满天繁星。
一个游戏模式对映着一套特定的 UI 布局和按键绑定。比方说玩家打开物品栏进入 `InventoryMode` 之后,屏幕上显示一排物品名称,按 `下方向键` 高亮列表中的下一个物品。但是在 `NormalMode` 里,物品栏被隐藏了,只有地下城是可见的,按 `下方向键` 将移动玩家人物。`GameModeManager`帮助我们方便地切换 UI 和输入方式。
首先,我们使用 `enum` 类型的数据标签来定义游戏模式。比方说,`GameModeTag.NormalMode`,`GameModeTag.ExamineMode` 和 `GameModeTag.StartMode`。接下来我们定义接口 `IGameModeManager`:
我们在 `GameModeManager` 内部设置 `CurrentGameMode` 的初始值。使用 `SwitchGameMode()` 发布两个事件(`SwitchingGameMode` 和 `SwitchedGameMode`)通知其它游戏组件,然后改变 `CurrentGameMode`。`SwitchGameModeEventArgs` 这个事件参数包括三个只读属性:`LeaveMode` 和 `EnterMode`是必需的属性,前者是当前游戏模式,后者是改动后的新模式;`CommandTag` 是可选的,有时候除了新旧游戏模式,我们还想知道模式改变时玩家按了什么键。
某个 UI 组件订阅了上述两个事件并修改自身状态。比方说,我们为了让 `Canvas_Message` 仅仅在 `NormalMode` 里在屏幕右下角显示最新的战斗日志,让它订阅了 `SwitchingGameMode`:
如何根据游戏模式改变按键绑定?这个问题留到下一节讨论。
输入系统监听玩家输入;把输入转化成 `enum` 类型的自定义命令,比如 `CommandTag.Confirm`,`CommandTag.Left` 或者 `CommandTag.SkillQ`;最后发布事件通知其它游戏组件。首先看一下输出部分。我们使用 `InputManager.Update()` 不断发布事件 `PlayerInputting`。
现在还剩下三个问题。首先,怎样实现 `InputManager.ConvertInput()`?其次,如何让两个输入(比如 `左方向键` 和 `h`)输出同一个命令(`CommandTag.Left`)?最后,怎样让多个游戏模式回应同一个命令,怎样在某个游戏模式里禁用特定命令?比方说,如何使得 `CommandTag.Left` 在 `NormalMode` 和 `InventoryMode` 里都有效,但是只允许 `InventoryMode` 响应 `空格键`?
“输入-命令”转换系统包含两个部分:输入转换器和基于模式的输入管理器。转换器统一命名为 `XInput`,实现了接口 `IConvertInput`。每个转换器接受玩家输入,输出一组彼此关联的命令——`LogInput` 输出和浏览日志有关的命令,`MovementInput` 输出和移动方向有关的命令。在以下代码里,请注意多个输入被转化成同一个输出,由此解决了第二个问题。另外,`CommandTag.INVALID` 是所有转换器默认的输出命令。
基于模式的输入管理器统一命名为 `XInputManager`,实现了接口 `IInputManager`,负责按特定顺序组合多个转换器。
先来实现 `InputManager.ConvertInput()`。接下来,如果整个游戏中只用到一个输入管理器 `PCInputManager`,我们可以这样修改 `InputManager.Update()`。
但实际情况是,我们在 `NormalMode` 里使用 `PCInputManager`,在 `AimMode` 里使用 `AimMarkerInputManager`。因此,我们给 `InputManager` 添加 `private Dictionary<GameModeTag, IInputManager> modeInputDict`,这个字典把游戏模式和输入管理器对应起来。`InputManager.Update()` 的最终版本如下。
上述代码已经解决了前文的第三个问题,这里再解释一下。只要给 `NormalModeInputManager` 和 `InventoryModeInputManager` 添加 `MovementInput`,两个输入管理器都能响应方向键。另一方面,假如 `ConfirmInput` 能够把 `空格键` 转换成确认命令,并且 `NormalMode` 和 `NormalModeInputManager` 相关联,那么只要不给 `NormalModeInputManager` 添加 `ConfirmInput`,在 `NormalMode` 里按 `空格键` 是无效的。
评论区
共 8 条评论热门最新