7.0 KiB
7.0 KiB
14 · 叙事系统规范
所属文档集 ← 返回索引
摘要:对话系统、世界标记、NPC 状态管理与三结局触发逻辑。
目录
1. 叙事设计原则
| 原则 | 说明 |
|---|---|
| 环境叙事优先 | 通过场景、图鉴和道具描述讲述故事,减少强制对话 |
| 非线性探索 | 玩家可按任意顺序解锁叙事内容 |
| 状态感知 | NPC 的对话随玩家进程改变(不重复同一句话) |
| 数据驱动 | 所有对话树、条件和触发均为数据,不硬编码 |
2. 对话系统
2.1 对话数据模型
DataModel DialogueData {
dialogueId : ID
speakerId : ID // NPC ID 或 "player"
──────────────────────────────────
nodes : List<DialogueNode>
entryNodeId : ID // 起始节点
}
DataModel DialogueNode {
nodeId : ID
type : DialogueNodeType // Text / Choice / Condition / Action
──────────────────────────────────
// type = Text:
text : Optional<String> // 支持本地化 Key
portrait : Optional<PortraitID>
nextNodeId : Optional<ID> // null = 对话结束
// type = Choice:
choices : Optional<List<DialogueChoice>>
// type = Condition:
condition : Optional<DialogueCondition>
trueNodeId : Optional<ID>
falseNodeId : Optional<ID>
// type = Action:
action : Optional<DialogueAction>
nextNodeId : Optional<ID>
}
DataModel DialogueChoice {
choiceText : String
nextNodeId : ID
availableCondition: Optional<DialogueCondition> // null=始终显示
}
2.2 对话条件类型
DataModel DialogueCondition {
conditionType : DialogueConditionType
targetId : Optional<ID>
value : Optional<Number>
}
| 条件类型 | 说明 |
|---|---|
HasAbility |
玩家已解锁某能力 |
HasItem |
玩家持有某物品 |
WorldFlagTrue |
某世界标记为 true |
QuestStageIs |
某任务处于指定阶段 |
BossDefeated |
某 Boss 已被击败 |
FirstVisit |
玩家第一次和此 NPC 对话 |
2.3 对话动作类型
| 动作类型 | 说明 |
|---|---|
SetWorldFlag |
设置世界标记 |
GiveItem |
给予物品 |
GiveGeo |
给予 Geo |
UnlockAbility |
解锁能力 |
AdvanceQuest |
推进任务阶段 |
PlayCutscene |
播放过场动画 |
3. 世界标记系统
3.1 世界标记规范
WorldFlags: Map<String, Boolean>
- 存储于
ProgressionSaveData.worldFlags - Key 为字符串,建议命名格式:
区域_事件_描述(如region1_boss_firstEncounter) - 标记只能设为 true,不支持撤销(设计保证单向性)
- 叙事系统、门控系统、AI 系统均可读取世界标记
3.2 设置世界标记的来源
| 来源 | 说明 |
|---|---|
对话动作 SetWorldFlag |
对话选择/到达某节点时触发 |
| 门控开启 | 某些门控开启时自动设置 |
| Boss 死亡 | OnBossDefeated 事件触发时自动设置 |
| 收集品拾取 | 特定关键收集品触发 |
| 手动触发器 | 场景中的触发区域触碰时 |
4. NPC 状态管理
4.1 NPC 数据模型
DataModel NPCData {
npcId : ID
displayName : String
──────────────────────────────────
locations : List<NPCLocationEntry> // NPC 在不同阶段的位置
dialogueVersions: List<NPCDialogueVersion> // 不同进程阶段的对话
}
DataModel NPCLocationEntry {
condition : Optional<DialogueCondition> // 满足时位于此处(null=默认)
roomId : ID
position : Vector2
}
DataModel NPCDialogueVersion {
condition : Optional<DialogueCondition> // 满足时使用此对话(null=默认)
dialogueId : ID
priority : Integer // 多个条件同时满足时取最高优先级
}
4.2 对话版本选取规则
玩家与 NPC 交互时:
枚举 NPCData.dialogueVersions(按 priority 降序)
→ 找第一个 condition 满足(或 condition 为 null)的版本
→ 使用该版本的 dialogueId 开始对话
若无任何版本满足 → 使用默认兜底对话("......")
5. 任务系统
5.1 任务数据模型
DataModel QuestData {
questId : ID
displayName : String
description : String
──────────────────────────────────
stages : List<QuestStageData>
rewardOnComplete: Optional<QuestReward>
}
DataModel QuestStageData {
stageIndex : Integer
description : String
completionCondition: DialogueCondition // 推进到下一阶段的条件
}
DataModel QuestReward {
geoAmount : Optional<Integer>
itemIds : List<ID>
abilityId : Optional<ID>
worldFlagsToSet : List<String>
}
6. 结局触发系统
6.1 结局条件回顾
(详细条件见 09_ProgressionSystem.md 第 5 节)
| 结局 | 类型 | 核心条件 |
|---|---|---|
| 结局 A | 普通 | 击败最终 Boss |
| 结局 B | 完全 | Boss 全清 + 主线剧情完整 + 关键 NPC 任务 |
| 结局 C | 隐藏 | 结局 B + 隐藏世界标记序列激活 |
6.2 结局判定流程
最终 Boss 死亡时:
检查结局 C 条件(最严格)
├─ 满足 → 触发结局 C
└─ 不满足 →
检查结局 B 条件
├─ 满足 → 触发结局 B
└─ 不满足 → 触发结局 A
触发结局 X:
→ 发出 OnEndingTriggered 事件(endingType)
→ 播放对应过场动画序列
→ 记录到 SaveData(endingUnlocked)
→ 游戏结束流程
7. 叙事事件目录
| 事件 | 触发时机 | 载荷 |
|---|---|---|
OnDialogueStarted |
开始对话 | dialogueId, npcId |
OnDialogueNodeReached |
到达对话节点 | nodeId |
OnDialogueChoiceMade |
玩家做出选择 | choiceIndex, nextNodeId |
OnDialogueEnded |
对话结束 | dialogueId |
OnWorldFlagSet |
世界标记变更 | flagKey |
OnQuestStarted |
任务开始 | questId |
OnQuestAdvanced |
任务推进 | questId, newStage |
OnQuestCompleted |
任务完成 | questId |
OnEndingTriggered |
结局触发 | endingType |
OnCutsceneStarted |
过场动画开始 | cutsceneId |
OnCutsceneEnded |
过场动画结束 | cutsceneId |