18 KiB
Lucky Dice 核心流程架构蓝图
文档信息
- 来源 PRD:lucky-dice-core-flow-prd.md
- 关联需求:lucky-dice-core-flow-requirements.md
- 关联规格:lucky-dice-core-flow-spec.md
- 适用项目:FishDice Unity 项目
- Unity 版本:2022.3.62f2c1
- 生成日期:2026-06-22
本文档定义 Lucky Dice 第一版核心闭环的架构蓝图。它不替代需求或接口规格,而是回答后续实现时最容易失控的几个问题:
- 普通 Roll、组合规则、Lucky Dice、目标玩法入口之间怎么分层。
- 哪些模块可以通过配置扩展,哪些模块才需要新增代码。
- 数据从玩家 Roll 到最终玩法模式如何流动。
- 追踪、兜底、测试和 Unity 落地目录应如何组织。
当前项目尚未落地生产 C# 玩法模块,因此本文档描述的是第一版建议架构,而不是对现有代码的复盘。
架构定位
Lucky Dice 不是普通骰子的二次 Roll,也不是一个独立短玩法本体。它在架构中承担的是“特殊玩法入口选择器”职责:
普通 Roll 负责产出组合事实
组合规则负责决定业务行为
Lucky Dice 负责从特殊结果池中选择目标入口
目标玩法模块负责执行 Slap Down / Treasure Heist 等具体内容
第一版架构应优先保证三件事:
- 可扩展:新增组合、骰子数量、特殊结果、目标玩法模式时优先改配置。
- 可测试:组合事实、规则匹配、筛选、权重随机都能用确定性输入测试。
- 可追踪:一次 Roll 的所有关键决策能用同一个
RollSessionId串起来。
架构原则
两套骰子集合隔离
普通骰子集合只表达主循环 Roll 的结果,例如 2 / 3 / 4 / 5 / 6 / clover。Lucky Dice 特殊结果集合只表达后续玩法入口,例如 rocket / thief。
两者不能混用同一套裸字符串,也不能让普通组合匹配器直接处理 Lucky Dice 特殊结果。
规则匹配先于行为执行
普通 Roll 结果必须先转换成结构化 ComboFacts,再交给规则匹配器。业务行为不应读取“左骰 / 右骰”这类固定位置状态。
DiceRollResult
→ ComboFacts
→ ComboRule
→ RollActionSpec
→ IRollActionExecutor
配置增长优先于代码增长
组合数量增加时,应增加 ComboRule 配置。只有出现新的通用匹配能力时才新增 matcher,只有出现新的通用业务行为时才新增 executor。
禁止形成下面这种随组合数量膨胀的结构:
clover_clover -> TriggerLuckyDice()
2_clover -> GrantCloverReward()
3_clover -> GrantCloverReward3()
...
流程服务不依赖表现层
核心流程可以产出展示所需数据,例如 Lucky Dice 标题、倍率、结果槽和目标玩法反馈,但不能依赖 UI 动画完成时序来做核心决策。
第一版表现层只消费核心结果,不参与筛选、随机和模式解析。
总览图
flowchart TD
Player["玩家触发 Roll"] --> RollService["DiceRollService"]
RollService --> FactBuilder["ComboFactBuilder"]
FactBuilder --> RuleMatcher["ComboRuleMatcher"]
RuleMatcher --> ActionDispatcher["RollActionDispatcher"]
ActionDispatcher --> Reward["RewardExecutor"]
ActionDispatcher --> Multiplier["MultiplierExecutor"]
ActionDispatcher --> LuckyTrigger["TriggerLuckyDiceExecutor"]
LuckyTrigger --> LuckyFlow["LuckyDiceFlowService"]
LuckyFlow --> CandidateFilters["CandidateFilters"]
CandidateFilters --> WeightedPicker["WeightedPicker"]
WeightedPicker --> SlotBuilder["ResultSlotBuilder"]
SlotBuilder --> ModeResolver["TargetModeResolver"]
ModeResolver --> Launcher["TargetModeLauncher"]
Launcher --> TargetGameplay["Slap Down / Treasure Heist"]
TargetGameplay --> MainLoop["回到主循环"]
RollService -.-> Trace["RollTrace"]
RuleMatcher -.-> Trace
ActionDispatcher -.-> Trace
LuckyFlow -.-> Trace
ModeResolver -.-> Trace
分层架构
| 层级 | 主要职责 | 允许依赖 | 禁止依赖 |
|---|---|---|---|
| 配置层 | 提供骰子集合、规则、候选结果、目标模式映射 | Unity 资源、本地 JSON、静态配置 | UI 动画状态、运行时随机结果 |
| Roll 层 | 根据 DiceSet 生成普通骰子结果 | 配置层、随机源 | 规则、奖励、玩法入口 |
| 组合事实层 | 把普通 Roll 结果转为统计事实 | Roll 层数据 | Lucky Dice 特殊结果、UI |
| 规则匹配层 | 按 matcher 和优先级命中规则 | 组合事实、规则配置 | 行为执行器、目标玩法 |
| 行为执行层 | 按 action type 分发通用行为 | 规则结果、上下文服务 | 组合 key 到独立方法映射 |
| Lucky Dice 层 | 候选池、筛选、权重随机、结果槽 | 候选配置、上下文、随机源 | 普通组合 matcher |
| 模式解析层 | ResultKey -> TargetKey -> ModeKey |
Lucky Dice 结果、上下文、模式配置 | 短玩法内部实现 |
| 表现层 | 展示 Lucky Dice 标题、倍率、结果槽、跳转反馈 | 核心流程产物 | 核心规则决策 |
| 目标玩法层 | 执行 Slap Down / Treasure Heist 等玩法 | TargetModeEntry | Lucky Dice 随机细节 |
| 追踪层 | 汇总关键决策链路 | 所有核心层事件 | 改变玩法结果 |
依赖方向应从上游输入流向下游结果。追踪层可以被各层写入,但不应反向影响流程决策。
组件职责
DiceSetConfigProvider
负责提供骰子集合配置,包括普通骰子面、普通骰子数量、Lucky Dice 特殊结果面、默认结果槽数量。
第一版可以使用 ScriptableObject、JSON 或硬编码本地配置启动,但调用方必须只通过 provider 读取,不把 2 颗骰子或 3 个结果槽写死到流程逻辑中。
DiceRollService
负责按骰子集合配置生成 Roll 结果。普通 Roll 会产出多个普通骰子面;Lucky Dice 第一版不需要真的 Roll 三颗特殊骰,而是由候选选择结果再生成展示槽。
该服务只负责“随机出可见骰子面”,不负责奖励、倍率或玩法入口。
ComboFactBuilder
负责把普通 Roll 结果转成 ComboFacts:
- 原始面列表
- 面数量统计
- 数字列表
- 点数和
- Clover 数量
- 无序归一化 key
- 有序 key
它必须支持 N 颗骰子。2 + clover 与 clover + 2 的无序 key 必须一致。
ComboRuleMatcher
负责把 ComboFacts 与规则配置匹配。matcher 按类型注册,例如 ExactCombo、AllNumbers、ContainsFace、FaceCountRange。
第一版按优先级从高到低匹配,默认命中高优先级规则后停止继续匹配,除非规则配置声明可以继续匹配。
RollActionDispatcher
负责把命中规则中的 RollActionSpec 分发给对应 executor。
dispatcher 只能维护 ActionType -> Executor 注册表,不能维护组合 key 到方法的映射。
LuckyDiceFlowService
负责 Lucky Dice 的核心入口选择流程:
构建候选池
→ 筛选候选池
→ 处理空池兜底
→ 权重随机
→ 生成展示结果槽
它不直接启动 Slap Down 或 Treasure Heist,而是把选中结果交给模式解析层。
TargetModeResolver
负责把 Lucky Dice 结果解析到具体目标玩法模式。
第一版映射:
| ResultKey | TargetKey | ModeKey |
|---|---|---|
rocket |
slap_down |
slap_down_normal |
thief |
treasure_heist |
treasure_heist_normal |
后续教程模式、bonus 模式应通过 mode rule 扩展,而不是在 Lucky Dice 随机代码里写分支。
TargetModeLauncher
负责统一启动目标玩法。它接收 TargetModeEntry,把 Lucky Dice 的结果、倍率、触发来源、RollSessionId 传给目标玩法入口。
目标玩法结束后,通过明确的 completion 回调或流程事件回到主循环。
RollTrace
负责记录一次 Roll 的关键路径。追踪不是埋点管线本身,第一版可以是本地结构化日志或调试面板数据。
最小字段应覆盖:
- 原始普通骰子结果
- 组合事实和归一化 key
- 命中规则和执行行为
- Lucky Dice 初始候选、过滤过程、兜底类型
- 权重随机输入和选中结果
- 解析出的 TargetKey 和 ModeKey
- 最终结果
核心数据流
普通 Roll
sequenceDiagram
participant P as Player
participant R as DiceRollService
participant F as ComboFactBuilder
participant M as ComboRuleMatcher
participant A as RollActionDispatcher
participant T as RollTrace
P->>R: Roll(normal_main)
R->>T: record normal faces
R->>F: DiceRollResult
F->>T: record ComboFacts
F->>M: ComboFacts
M->>T: record matched rule
M->>A: RollActionSpec list
A->>T: record executed actions
Lucky Dice
sequenceDiagram
participant A as TriggerLuckyDiceExecutor
participant L as LuckyDiceFlowService
participant F as CandidateFilters
participant W as WeightedPicker
participant S as ResultSlotBuilder
participant M as TargetModeResolver
participant T as RollTrace
A->>L: LuckyDiceContext
L->>T: record initial candidates
L->>F: apply filters
F->>T: record filter decisions
F->>W: filtered candidates
W->>T: record random value and selected result
W->>S: selected candidate
S->>T: record result slots
S->>M: selected candidate + context
M->>T: record target mode
配置架构
第一版建议至少拆成四类配置:
| 配置 | 示例内容 | 扩展方向 |
|---|---|---|
| DiceSetConfig | normal_main、lucky_dice、骰子面、骰子数量、默认槽数 |
支持关卡自定义骰子数量 |
| ComboRuleConfig | 规则 id、优先级、matcher、actions | 策划新增组合语义 |
| LuckyDiceCandidateConfig | result、target、weight、enabled、slot count、default | 扩展特殊结果与概率 |
| TargetModeConfig | target、default mode、tutorial mode、bonus mode | 扩展玩法模式 |
配置读取顺序建议:
本地默认配置
→ 关卡或活动覆盖配置
→ 运行时上下文修正
远端热更不在第一版范围内,但数据结构应避免与 Unity 场景对象强绑定,给后续迁移到远端配置留出空间。
Unity 落地目录建议
如果第一版开始实现 C# 模块,建议按运行时核心、配置、表现、测试分开:
FishDice/Assets/FishDice/
Runtime/
LuckyDice/
Core/
DiceRollService.cs
ComboFactBuilder.cs
ComboRuleMatcher.cs
RollActionDispatcher.cs
LuckyDiceFlowService.cs
TargetModeResolver.cs
Config/
DiceSetConfig.cs
ComboRuleConfig.cs
LuckyDiceCandidateConfig.cs
TargetModeConfig.cs
Actions/
GrantRewardExecutor.cs
AddMultiplierExecutor.cs
TriggerLuckyDiceExecutor.cs
EnterModeExecutor.cs
Filters/
EnabledFilter.cs
ProgressFilter.cs
SourceFilter.cs
CooldownFilter.cs
TutorialFilter.cs
Presentation/
LuckyDicePresenter.cs
LuckyDiceResultSlotView.cs
Trace/
RollTrace.cs
RollTraceLogger.cs
Tests/
EditMode/
LuckyDice/
第一版核心流程建议尽量放在纯 C# 类里,减少对 MonoBehaviour 的依赖。表现层再通过 Unity 组件消费核心流程产物。
错误处理与兜底
普通组合未命中
处理策略:
- 记录
RollSessionId、原始骰子面、NormalizedKey。 - 走普通奖励兜底,或在调试模式返回明确错误。
- 不进入 Lucky Dice。
Lucky Dice 候选池为空
处理策略:
- 尝试使用配置的 default result。
- default result 不可用时,降级为普通奖励兜底。
- 记录每个 filter 过滤前后的候选数量和空池原因。
模式解析失败
处理策略:
- 记录
ResultKey、TargetKey和上下文。 - 尝试使用目标玩法默认模式。
- 仍失败时降级为普通奖励兜底,并标记为配置错误。
兜底必须可观测,不能静默吞掉。否则后续配置错误会表现成“玩家只是没进 Lucky Dice”,很难定位。
测试架构
测试应围绕外部行为和完整链路,而不是私有实现细节。
单元测试
| 测试对象 | 重点 |
|---|---|
| ComboFactBuilder | N 骰统计、无序 key、有序 key、Clover 数量 |
| ComboRuleMatcher | 优先级、matcher 类型、停止继续匹配 |
| RollActionDispatcher | 按 action type 分发,不按 combo key 分发 |
| CandidateFilters | enabled、progress、source、cooldown、tutorial 过滤 |
| WeightedPicker | 固定随机源下结果可预测 |
| TargetModeResolver | rocket/thief 映射和默认模式 |
链路测试
链路测试是第一版最重要的测试口:
给定 Roll 请求
给定 DiceSet 配置
给定 ComboRule 配置
给定 Lucky Dice 候选池
给定固定随机源
断言最终 outcome
最小链路用例:
2 + 3发普通奖励。2 + clover发普通奖励并提供 Clover bonus。clover + clover触发 Lucky Dice。- Lucky Dice 选中
rocket后进入slap_down_normal。 - Lucky Dice 选中
thief后进入treasure_heist_normal。 - 候选池为空时进入可观测兜底。
- 普通骰子数量改成 3 后,组合事实和 matcher 仍可工作。
架构决策记录
完整 ADR 存放在 Docs/Decisions。本节只保留摘要,后续决策变更应优先新增或更新独立 ADR 文档。
ADR-001:普通骰子和 Lucky Dice 特殊结果分成两套集合
上下文:普通骰子负责奖励组合,Lucky Dice 负责玩法入口。两者语义不同。
决策:使用 DiceSetType.Normal 和 DiceSetType.Lucky 区分集合,不让普通组合匹配器处理 Lucky Dice 特殊结果。
结果:避免数字结算和玩法入口混用。代价是配置和调试界面需要明确展示集合类型。
ADR-002:Roll 结果先转组合事实,再匹配规则
上下文:第一版默认 2 颗骰子,但未来需要支持 3 颗、4 颗或关卡自定义骰子数量。
决策:所有普通 Roll 都先生成 ComboFacts,matcher 只依赖事实统计,不依赖固定位置。
结果:后续扩骰数量时风险更低。代价是第一版需要多写一层事实构建和测试。
ADR-003:行为按 action type 注册
上下文:如果每个组合 key 绑定一个独立方法,组合增长会让执行层失控。
决策:规则只声明 action 列表,dispatcher 只按 ActionType 找 executor。
结果:新增组合多数情况下只改配置。代价是 action 参数需要有清晰校验。
ADR-004:Lucky Dice 随机源可注入
上下文:权重随机必须可测试、可回放。
决策:Lucky Dice 权重随机通过 IRandomSource 或等价接口注入随机源。
结果:测试可预测,线上问题可复盘。代价是运行时需要统一管理随机源生命周期。
新功能开发蓝图
新增普通组合
- 确认现有 matcher 能否表达该组合。
- 能表达时新增
ComboRuleConfig。 - 需要新业务效果时,优先复用现有 action。
- 只有确实出现新的通用行为时,新增 executor。
- 补一条规则匹配测试和一条链路测试。
新增 Lucky Dice 特殊结果
- 在 Lucky Dice 特殊结果集合中新增
ResultKey。 - 在候选配置中声明
TargetKey、权重、启用条件、槽数、default 标记。 - 在目标模式配置中声明默认
ModeKey。 - 补候选筛选测试、权重随机测试和目标模式解析测试。
新增目标玩法模式
- 在
TargetModeConfig中增加模式映射。 - 如模式选择依赖上下文,新增 mode rule。
- 不修改 Lucky Dice 随机逻辑。
- 补
TargetModeResolver测试。
接入表现动画
- 核心流程先产出
LuckyDiceResultSlots和TargetModeEntry。 - 表现层播放标题、倍率、结果槽和跳转反馈。
- 动画完成后再调用 launcher,或先启动目标玩法再做过场,取决于产品节奏。
- 动画失败不能改变核心选择结果。
架构治理
实现和评审时重点检查以下规则:
- 核心流程中没有固定读取第 0/1 颗骰子的业务判断。
- 普通骰子和 Lucky Dice 特殊结果没有混用同一套集合。
- 新增组合时没有新增组合 key 到独立方法的 map。
- Lucky Dice 候选必须先筛选再随机。
- 候选池为空、模式解析失败、未命中规则都有可观测兜底。
RollSessionId贯穿普通 Roll、规则匹配、Lucky Dice、模式解析、目标玩法启动。- 表现层不参与规则匹配、候选筛选和权重随机。
第一版落地顺序
建议按以下顺序实现:
- 定义核心数据结构和本地默认配置。
- 实现普通 Roll、组合事实和规则匹配。
- 实现 action dispatcher 和普通奖励 / Clover bonus / trigger Lucky Dice 执行器。
- 实现 Lucky Dice 候选筛选、权重随机、结果槽生成。
- 实现
rocket -> slap_down_normal和thief -> treasure_heist_normal模式解析。 - 实现最小表现层:标题、倍率、结果槽、目标玩法跳转反馈。
- 补齐链路测试和追踪字段。
这个顺序能先把核心闭环跑通,再逐步加表现和更多结果类型,避免一开始被动画和短玩法完整内容拖散。