在我们日常的教育类游戏(DGBL)开发中,经常会遇到极其庞大的同类知识点对象。比如烹饪玩法里的几十种食材、化学实验里的 118 种元素、或者是语言学习里的海量词根词缀。
如果在 Unity 中为每一种 “面条”、“番茄” 或 “氧元素” 单独制作一个 Prefab(预制件)并编写独立的控制脚本,工程将迅速膨胀。后续教研同学想要修改属性时,也会因为满屏的代码而无从下手。
为了解决这个痛点,我们在近期的项目中引入了数据驱动设计结合 ** 有限状态机(FSM)** 的架构。通过将 “数据” 与 “表现容器” 彻底剥离,实现了一套对团队协作极其友好的高复用性系统。
# 1. 核心架构拆解:享元模式下的数据与容器分离
在传统的面向对象编程中,我们习惯于把属性和方法写在同一个脚本里挂载给物体。但在这里,我们借鉴了享元模式(Flyweight Pattern)的思想:将成百上千个物体中不变的逻辑外壳提取为通用容器,将变化的数据抽离为独立配置。
# 1.1 定义静态数据模板:ScriptableObject
首先,我们摒弃了在 MonoBehaviour 里直接写死属性的做法,利用 Unity 的 ScriptableObject 定义了一个纯数据类 FOODSO 。
这相当于一个 “模具”,它不参与场景运行,只负责存储各类属性定义:
1 | [] |
设计红利: 所有的知识点数据都变成了 Project 文件夹里的轻量级 .asset 资源文件。团队里的同学只需要在后台右键创建对应的数据体并 “填表”、配图即可。完全零代码,实现了程序与策划工作流的彻底解耦。
# 1.2 构建通用视觉容器
我们不需要制作几十个预制件,整个项目中维护的实体 Prefab 永远只有 1 个。
它是一个极其干净的空壳,仅包含基础的排版组件和负责显示的 Image 子节点。对应的控制脚本只暴露一个简单的注入接口:
1 | using UnityEngine; |
# 2. 行为解耦:基于状态模式的无差别交互台
解决了 “物体是什么” 的问题后,我们需要处理交互逻辑(比如把食材扔进锅里,或者把元素扔进反应炉)。这部分的难点在于防止玩家的异常操作(比如菜已经煮熟了还在往里加料,导致逻辑崩溃)。
针对这个问题,我们利用 ** 有限状态机(FSM)** 设计了统一的交互组件。交互台本身对具体放入的是什么一无所知,它只认 FOODSO 这种数据结构,并在三个严谨的状态间流转: Idle (空闲)、 Processing (处理中)、 Finished (已完成)。
# 状态机的封闭性与安全性验证
1 | using UnityEngine; |
在 Update() 的生命周期中,倒计时逻辑被严格包裹在 Processing 状态下。一旦时间达到判定阈值,内部触发完成逻辑切断计时,并将状态推至 Finished ,等待玩家取走成品后重置状态,重新回归 Idle 。
# 3. 跨项目复用场景
这套 “通用容器 + 数据体 + 状态机交互台” 的系统非常纯粹,可以迅速平移至以下场景:
-
化学 / 物理实验沙盒: *
FOODSO变为ElementSO(包含化学式、外观、反应耗时)。- 交互台变为
Reactor_Prefab(反应炉)。 - 玩家将不同元素拖入反应炉,状态机鉴权后开始读取配方倒计时,最终生成新的化合物实体。
- 交互台变为
-
语言文字建构玩法: *
FOODSO变为WordSO(包含词根、词缀文本及发音音频)。- 交互台变为
GrammarSlot_Prefab(语法判定槽)。 - 判定槽通过状态机拦截非法的词缀组合,并在组合成功后播放对应的正向反馈和发音。
- 交互台变为
采用这种架构,不仅降低了运行时的渲染和内存压力,更重要的是它为团队协作铺平了道路 —— 底层逻辑的舞台搭好后,后续关卡内容的扩充仅仅是填表而已。