Kirino 的游戏宝藏
← 返回第 022 期
游戏观察

信号向上与门前的队列:Ben (RNG) 如何用 composition,把《Memento Manor》的独作噩梦钉成可协作的下一局

如果说过去十余年里,独立游戏开发者写事后复盘时,默认剧本常常是「我一个人扛完了程序、美术、音乐与文案,然后在结尾说下次还是别独作」,那么 2026 年九月十日,Ben(署名 RNG)在 itch.io 上摊开的那篇《Memento Manor - A Paranormal Postmortem Introspection》…

我的收藏 ↗

如果说过去十余年里,独立游戏开发者写事后复盘时,默认剧本常常是「我一个人扛完了程序、美术、音乐与文案,然后在结尾说下次还是别独作」,那么 2026 年九月十日,Ben(署名 RNG)在 itch.io 上摊开的那篇《Memento Manor - A Paranormal Postmortem Introspection》,几乎是在当众改写这套账单的结算方式。作品叫《Memento Manor》,俯视角灵异 RPG,任务制庄园,玩家扮演超自然调查员 Mara Kalina,在被「居民」盘踞的记忆里找失窃的 Memento。引擎是 Godot,脚本从上一作 Phantom Forest 的 GDScript 切到 C# / .NET。本稿未试玩成品,以下场面与机制均来自作者公开复盘与游戏页资料观察。

贯穿本稿的意象,是「信号向上」与「门前的队列」。前者听起来像场景树纪律,落到制作伦理上,却是一组可核验的解耦承诺:子节点不必认识父节点也能发声,父节点按需向下取引用。后者听起来像工程笑话——业界都知道门会把程序员拖进泥潭——落到 Ben 的复盘里,却是独作最诚实的战场:同一扇门要服务 Open、Peek、Loud Knock,还要让多名居民排队通过,还要在有人偷看时被居民撞开后强制退出。独作的重量,不是口号里的「全能」,而是这些机制被逐项钉死之后,作者才敢说:下一局,我想协作。

《Memento Manor》封面:庄园与调查者

一、默认逻辑:独作等于全能,全局管理器等于省事

行业默认逻辑其实很干净,也因此很偷懒。

一个人做完整游戏,团队通常会打开一张熟悉的菜单:把所有持久状态塞进一个巨大的 Game Manager;用场景继承复制关卡树,好让「加一个节点」自动扩散到所有关卡;交互物件只挂一个「按 E 互动」;NPC 路径写死成从 A 走到 B;俯视角「看起来像贴图」就算过关。玩家也学会了用同一套语汇阅读独作——他们会说「能玩就行」「程序员美术有味道」「门的动画卡一下没关系」。这种默契让「独作的粗糙」变成可被原谅的行业语法。

《Memento Manor》偏偏是最难被这套语法容纳的作品之一:整座庄园按房间切分渲染与碰撞;居民有 Routine / Search / Chase / Sleep / Wander / Stunned / Trapped 一整套状态;调查任务靠 Investigation 结构体定制房间、居民、门连接与拾取物;玩家还有 Walk / Run / Idle / Busy / Peek / Faint。它最初对准的,是「完整体验」而不是「能开演示」。把这样的作品塞进一个人的工期,行业直觉几乎会自动指向「砍系统、砍门、砍第二层楼」。

Ben 的公开复盘却拒绝了那条捷径的自我安慰。他写得很直:独作工作量极大,他事前知道,但必须亲手看见「为什么」;他主要是程序员,最好的工作在幕后功能里,可一旦选择独作,音乐、图形与对白也得学。更关键的一句,不是自我感动,而是方向声明——他期待接下来做协作项目,因为独作让他摸清了其他工种的基本盘,协作时才能带着「对方流程」去写自己的那一块。分叉点就在这里。默认问的是,一个人扛不住时砍什么系统。他改问的是,一个人扛得住时,哪些解耦一旦写对,下一局协作才不会把同一套耦合再拖进泥潭。

二、砸碎脚本:信号向上、引用向下,以及状态机把「忙」说清楚

解耦容易声称,难证明。听起来稳赢的点子,往往是把所有东西都做成全局单例,或者把场景继承当成免费复制。Ben 带着上一作的经验进来:Phantom Forest 里已经用过 GDScript;这一作切到 C#,不只是为了「会另一种语言」,而是担心只写 GDScript 会限制未来引擎与 IDE 选择,而 .NET 版 Godot 能接 Visual Studio,也让他继续用大学时期熟悉的 C# 写法。复盘里他列得很具体:哈希表、静态数据、lambda、枚举、接口、结构体、继承、多态、空条件赋值、异步,以及自己写的 assert。用意写得很硬——既然用 C#,就不要把它当 GDScript 的皮。

C# 也带来必须付的账单。与 GDScript 即时清空不同,C# 垃圾回收成批、不频繁,刚清掉的引用仍可能被摸到;全局管理器里绝不能存非全局对象的引用,否则场景切换就漏内存;静态列表要复制再改,否则会污染所有居民共用的预建字典;连到全局信号的本地节点,必须在 `_ExitTree` 里手动断开——GDScript 常会在换场时清掉,C# 不会。这些不是抽象洁癖,而是独作里最容易在第三个月爆掉的那种「小 quirk」。

真正砸碎默认脚本的,是 composition 与那句纪律:**signal up, reference down**。子组件用信号向上汇报,不必知道父是谁;父若需要即时数据,向下持引用。HealthComponent 式的子节点可以挂到玩家或敌人;Interact Area 作为 Area2D 子节点,可挂到任意可交互物,父只连接「有人进入范围」的信号。风险也被作者写进同一段:组件文档差,系统之间会失明;解法是命名说清用途(如 HealthComponent)、组件短、职责单一。灵活不是免费的,它买的是「同一套小系统能被不同父复用」,付的是「你必须把接口写得像给人看的合同」。

状态机在这里不是教材名词,而是把「这一刻角色到底能不能动」钉成可继承的方法表。玩家侧:Walk / Run / Idle 处理移动与交互;Busy 在交互中收走移动权;Peek 额外允许门缝灯光移动,并在玩家输入、门被他人使用、或被居民看见时立刻退出并通知门复位;Faint 在被抓住后等晕厥动画与庄园内时间跳跃,并藏 UI。居民侧默认 Routine,按时间与位置走日程;NoiseArea 或火把进入听力 / 侦测范围则进 Search;射线确认视线则进 Chase;到达目的地后 Sleep 或 Wander;弱点与陷阱分别进 Stunned / Trapped 并常掉落 Memento。基类 State 上可覆盖的 Move / Turn 等,Busy 可以「什么都不做」,Walk 必须响应输入——复杂度被关进新状态,而不是摊进一个三千行的 `if`。

俯视角庄园内景:房间、光与可调查物

三、门、路由、Investigation:把「最难的系统」写成可定制任务

帧预算之外,独作最贵的往往是「一扇门」。Ben 直言:所有设计里,门经历的重做、微调与妥协最多;居民或许是最复杂的对象,门却从头到尾棘手。原因写得很土,也很准——门往往不止是关卡传送:它是可交互物,分隔环境,可被多种角色使用,还可锁定、偷看、大声敲门。每一种用途都要求状态变化,还要干净复位,还要通知其他角色「这扇门现在不可用」。

《Memento Manor》的门选了偏宝可梦式的淡入淡出过渡,而不是角色走进门洞再走出:开门精灵、角色淡出、移到对侧门标记、淡入、关门。可交互物共用 Action 系统,门挂三个标准槽:Open、Peek、Loud Knock。同一时刻只允许一个角色开门,优先于偷看;玩家偷看时若居民开门,玩家被强制退出 Peek,并等到居民通过与短延迟后才能再交互;多名居民抢门则进入队列,短延迟后重试,次数有限,超时则调用 unstuck 拉回日程位置。原本想做「走进门后藏在墙后走出」的动画,实测又慢又难,收益薄——于是砍掉。这不是浪漫叙事里的「坚持做完」,而是独作里最贵的诚实:过渡只要把「换房」说清楚,不必表演。

导航侧同样用具体结构压住「NPC 会走路」。每间房一个 NavigationRegion2D,家具与墙用 NavigationObstacle2D 挡,门用 NavigationLink2D 串网;居民带 goal 节点逐步走向门标记或终点。Route 是结构体:起点、途经房间列表、标记、过滤步骤的函数;靠预填的 connections 字典求最短路由,也支持自定义房间连接。状态机决定何时重算——Routine 每房一两次即可,Chase / Search 则对移动目标频繁更新。房间自己管渲染、碰撞、环境光与环境音:玩家进入才亮灯与图层;其他房的居民仍导航,但跳过视觉;碰撞在无人在房时可以关掉。更花的是「投影仪」:定制 SubViewport 把一间房的实时画面投到另一间「下方」,用来做大堂与阳台、花园与桥之间的楼层纵深——资料观察可见其意图,本稿未实测手感。

任务制的心脏是 Investigation 结构体。调查台选定任务后,庄园读这份结构:房间是否黑暗 / 锁定 / 禁用、门如何改接、居民类型与日程与难度、NPC 对白与位置、拾取物概率与顺序、玩家起始房与道具与理智。难度不是线性乘系数——居民 1–10 评级经 Curve 资源非线性采样到速度、理智伤害、侦测半径等。世界画面放在 960×540 的 SubViewport 里 ×2 拉伸对齐 1920×1080 UI,像素用 Nearest 过滤;Tween 与 AnimationPlayer 的分工写成一句可执行哲学:「最终值未知用 Tween,否则用 AnimationPlayer」。场景继承被作者明确降权:基场景强加节点会浪费与绑死,他更倾向 composition 搭场景,脚本继承留在对象内部。

俯视角的「不扁」也被写成可执行清单,而不是气氛形容词。脚底阴影按体型与高度压透明度;移动时 CPUParticles2D 扬尘给「重量」;Y-sorting 让玩家绕过 NPC 与物件时前后关系成立;近景墙与栏杆靠近则淡出,户外房可关掉淡出以保留包围感,黑暗房则默认淡前景,好让黑暗本身当主障碍。可交互物继承同一基类,最多三个 Action 槽,槽位可动态改写(锁门、进出衣柜),并带 action state 名,好让玩家立刻切到 Busy 或相应态;全局 Interaction Manager 作中间人,校验、互斥、结束时调用 clear。全局单例一侧,Game / Save / UI / Player / Audio / Item / Time / Interaction 各管一块——作者同时点名:Item 与 Time 今天更适合做成庄园本地对象,而不是处处可摸的单例。这不是事后谦虚,而是独作复盘里最稀缺的那种否决:多出来的全局,也会变成下一局协作时没人敢动的黑洞。

调查界面与任务定制信息

四、收束:独立等于愿意把独作做成下一局协作的教材

把这篇九月十日的复盘放回 2026 年秋天的 Godot 独作现场,它首先打击的是一种隐蔽的制作惯性。大家默认独作等于全能神话,默认全局单例越多越省事,默认门「能过」就够了,很少有人追问:你写的解耦,是在为一个人的下一周省事,还是在为多人的下一项目留接口。Ben 把另一条路径摊开。信号向上、引用向下可以写成纪律。状态机可以把 Busy / Peek / Faint 与 Chase / Search 关进各自的方法表。Investigation 结构体可以把「又一个任务」变成填表而不是复制关卡。门可以公开承认是噩梦,并留下队列与强制退出 Peek 的规则。Item Manager 与 Time Manager 他甚至自我检讨:今天会倾向做成庄园本地对象,而不是全局单例——独作复盘里,这种「我多做了」比「我全做了」更有用。

对小团队,这组材料尤其刺耳,也尤其有用。你未必有居民全状态表,也未必有 SubViewport 投影仪。你一定有自己的「默认已经够用」清单。某个交互只挂一个按键。某扇门没有队列,第二名 NPC 直接穿模。某个全局管理器存着本应随场景销毁的引用。某次从 GDScript 切到 C# 却忘了在 `_ExitTree` 断信号。某次俯视角只有背景贴图,没有脚底阴影、扬尘、Y-sort 与近景淡出。某次难度用线性乘法,却抱怨「高等级突然不公平」。Ben 的公开作业把成本写得很土:独作是为了摸清其他工种;原型可以继续一个人做,完整游戏他想协作;灵感来自《路易吉洋馆》《格雷戈里恐怖秀》《失忆症:黑暗后裔》《宝可梦白金》——本稿仅作资料标注,不代替游玩体验。itch 页写明 Windows / Linux、v1.0.0、No generative AI was used。

可执行的提示很短。

  • 在第一笔「全局管理器」提交前,先写一句纪律:哪些更新走信号向上,哪些数据走引用向下;临时节点连全局信号时,同步写 `_ExitTree` 断开。
  • 角色决策一旦超过三条互斥行为,先抽基类 State 与状态机组件,再往里加;Busy / 不可移动态要显式,不要靠散落的布尔。
  • 门、传送、多角色共用交互物,优先设计队列、互斥与强制退出条件,再谈动画是否「走进门洞」。
  • 任务变体用结构体(或等价数据)定制关卡,而不是复制场景树;难度用曲线采样,而不是线性乘到第十级才爆炸。
  • 独作若以「学会协作」为出口,把非长项工种的产出做成可交接的接口与命名,而不是只做成自己能改的魔法数。

信号向上、门前排队、Investigation 填表、以及一句「solo development is a lot of work」。在复盘仍公开、游戏仍可在 itch 下载之前,作者已经把审计标准说死了:不是「一个人能不能做完」,而是「做完之后,你有没有把下一局协作需要的解耦,留在仓库里」。

小光

来源与延伸阅读

Ben (RNG)(2026-09-10)Memento Manor - A Paranormal Postmortem Introspection

游戏页 Memento Manor(Windows / Linux,v1.0.0;标注 No generative AI was used)

登录后,留下你的阅读足迹。

在个人页查看自己的点赞和收藏,换设备也能继续。

登录