任务系统为什么容易失控
个人游戏进入中后期后,任务系统经常从几行变量变成一团状态。某个 NPC 对话后开门,拿到道具后刷新目标,击败敌人后播放过场,读档后又要恢复这些变化。早期写成 hasKey = true、doorOpened = true 没问题,但等 Steam Demo 或正式版需要稳定运行时,临时变量会让 bug 很难查。
任务系统的核心是状态机。玩家当前处于任务哪一步,什么条件能推进,推进后影响哪些系统,失败或读档后如何恢复,都要有明确规则。任务不是只给玩家看的目标文字,它还连接关卡、NPC、存档、成就、日志、商店页承诺和 QA。
先定义任务状态
不要从对话文本开始写任务,先定义状态:
| 状态 | 含义 |
|---|---|
inactive | 未激活,不显示给玩家 |
active | 已接取,显示当前目标 |
objective_done | 当前目标达成,等待提交或下一步 |
completed | 已完成,不再重复触发 |
failed | 已失败,可能进入替代分支 |
复杂任务可以有多个阶段:
factory_gate.inactive
factory_gate.find_key
factory_gate.restore_power
factory_gate.open_gate
factory_gate.completed
状态名要稳定,因为它会进入存档、日志和测试表。不要用“步骤 1”“步骤 2”这种难以理解的名字。三个月后看到 restore_power,你仍然知道它代表恢复工厂供电。
触发器要可追踪
任务推进通常来自触发器:进入区域、对话选择、获得道具、击败敌人、操作机关、时间结束。每个触发器都要能解释“谁触发了什么任务状态变化”。
建议记录触发表:
| 触发器 | 条件 | 结果 |
|---|---|---|
enter_factory_yard | 任务未激活,玩家进入工厂外院 | 激活 find_key |
pickup_gate_key | 当前阶段为 find_key | 进入 restore_power |
power_switch_on | 拥有钥匙且电源未恢复 | 进入 open_gate |
gate_opened | 门动画结束 | 完成任务 |
触发器不要分散在场景脚本里找不到。可以集中在任务配置或关卡事件表中,至少要在文档里能查到。否则读档问题和分支问题会非常难复现。
目标显示和真实状态分开
玩家看到的是目标文本,系统记录的是状态。不要把目标文字当作状态判断。目标文本需要本地化,也可能调整措辞;任务状态要稳定。
例如:
| 状态 | 文本 Key |
|---|---|
factory_gate.find_key | quest.factory_gate.find_key |
factory_gate.restore_power | quest.factory_gate.restore_power |
factory_gate.open_gate | quest.factory_gate.open_gate |
这样中文可以写“找到门卫室钥匙”,英文可以写“Find the guardroom key”,但代码只关心 find_key。语言切换时,UI 重新读取文本,不影响任务状态。
分支任务要少而清楚
分支能提升代入感,但也会显著增加测试成本。个人项目如果没有足够时间,任务分支要控制数量。每个分支都要回答:
- 是否影响后续关卡。
- 是否影响奖励。
- 是否影响成就。
- 是否需要不同存档字段。
- 是否需要不同对话和 UI 文本。
如果分支只改变一句台词,可以用轻量标记;如果分支影响地图、NPC 和结局,就需要完整测试路径。不要为了页面上写“选择影响故事”而加没有回收的分支。Steam 玩家会在后续内容里寻找选择后果。
任务和存档
任务状态必须进入存档。保存内容包括:任务 ID、当前阶段、已完成目标、关键变量、已触发一次性事件。不要只保存当前目标文字。
一个任务存档结构可以是:
{
"questId": "factory_gate",
"state": "restore_power",
"flags": {
"keyPicked": true,
"guardDialogSeen": true
}
}
读档后要恢复关卡状态:钥匙不再出现,NPC 对话变化,电源开关状态正确,门仍然关闭或打开。任务系统不能只恢复 UI,否则玩家会看到目标正确但世界状态错误。
任务日志和开发日志
玩家任务日志要清楚,开发日志要可排查。任务推进时建议写日志:
quest_change quest=factory_gate from=find_key to=restore_power trigger=pickup_gate_key
这行日志在玩家反馈“任务卡住”时很有用。你能看到任务是否推进、触发器是否触发、当前状态是否正确。任务系统和调试日志结合后,很多难复现问题会变得具体。
失败和异常路径
任务系统要考虑异常:玩家先拿到道具再接任务,玩家杀死 NPC,玩家跳过某段触发,玩家读旧存档,玩家退出时正在过场。不要只设计正常路径。
处理策略:
| 异常 | 策略 |
|---|---|
| 提前获得道具 | 接任务时检测并直接进入下一阶段 |
| NPC 不存在 | 提供替代提交点或阻止关键 NPC 死亡 |
| 触发器错过 | 进入区域时做状态校验 |
| 旧存档缺字段 | 迁移到合理默认状态 |
| 过场中退出 | 读档回到过场前稳定点 |
这些处理不一定复杂,但要提前想。任务卡死是玩家很难接受的问题,因为它阻断主流程。
QA 任务矩阵
任务 QA 不能只从头跑一次。要按阶段测试:
| 测试 | 目标 |
|---|---|
| 正常流程 | 从激活到完成 |
| 每阶段读档 | 检查 UI 和世界状态 |
| 提前条件 | 先拿道具再接任务 |
| 失败路径 | 放弃、死亡、退出 |
| 语言切换 | 目标文本刷新 |
| 手柄操作 | 对话和提交可完成 |
每个主线任务都应该有这样的矩阵。支线任务可以简化,但关键路径不能省。
和 Steam 页面承诺对齐
如果商店页写“分支任务”“NPC 会记住你的选择”“非线性探索”,任务系统就要支持这些承诺。不要把宣传语言写成系统做不到的事情。任务审计时,把页面卖点和任务实现对照,确认玩家能在前期体验到。
任务系统不只是内部工程问题,它会直接影响玩家是否相信游戏世界。
最终检查清单
- 任务使用稳定状态名,不依赖目标文字。
- 触发器有条件和结果记录。
- UI 文本通过本地化 Key 显示。
- 分支数量和测试能力匹配。
- 任务状态、标记和一次性事件进入存档。
- 任务推进写入开发日志。
- 异常路径有恢复策略。
- 主线任务有阶段读档 QA。
任务系统做得稳,玩家会自然向前推进;任务系统做得乱,游戏再有内容也会被卡流程拖垮。个人 Steam 项目越接近发布,越需要把任务从临时脚本整理成可维护系统。
任务编辑和可视化
如果任务数量超过十几个,可以考虑做简单可视化或导出表。个人项目不一定要做完整编辑器,但可以用表格列出任务 ID、阶段、触发器、目标文本、奖励和依赖。这样比在场景脚本里翻找更可靠。
表格还可以帮助本地化和 QA。翻译人员知道每个目标文本的上下文,测试人员知道每个阶段如何进入。任务系统越透明,后期维护越轻。
任务奖励要统一发放
任务完成后可能发金币、道具、经验、成就、剧情标记。建议通过统一奖励接口发放,并写日志。不要在对话脚本里发一次金币,在任务脚本里又发一次道具,后面很容易重复或漏发。
统一奖励还能处理背包满、资源上限、已拥有道具等边缘情况。玩家不会关心内部哪个脚本发奖励,只会关心结果是否合理。
任务重置和章节选择
如果游戏支持章节选择或重玩关卡,要考虑任务是否重置。主线任务可能不应重复发奖励,但关卡内临时目标需要恢复。重玩时哪些状态从全局存档读取,哪些从关卡初始化,是任务系统必须明确的问题。
没有规则时,重玩章节最容易出现 NPC 台词错乱、奖励重复领取、门状态不对等问题。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。