313 lines
8.4 KiB
Markdown
313 lines
8.4 KiB
Markdown
|
|
# 玩法编辑器系统 — 完整实现方案
|
|||
|
|
|
|||
|
|
## 系统架构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ GameplayEditorWindow (Editor) │
|
|||
|
|
│ ┌──────────────────────────┐ ┌────────────────────────────┐ │
|
|||
|
|
│ │ Canvas 可视化编辑 │ │ Excel 表格映射 │ │
|
|||
|
|
│ │ (FlowCanvas/NodeCanvas) │ │ (GraphDataSchema) │ │
|
|||
|
|
│ └──────────┬───────────────┘ └─────────────┬──────────────┘ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ └──────────────┬─────────────────┘ │
|
|||
|
|
│ │ │
|
|||
|
|
│ GraphExcelSyncManager (Runtime) │
|
|||
|
|
│ (双向同步: Graph JSON ↔ Excel 表格) │
|
|||
|
|
│ │ │
|
|||
|
|
│ ┌──────────────────┴──────────────────┐ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ ExcelDataProvider Graph.onGraphSerialized │
|
|||
|
|
│ (EPPlus 读写 .xlsx) (自动触发同步) │
|
|||
|
|
└─────────────────────────────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 核心模块说明
|
|||
|
|
|
|||
|
|
### 1. **GraphDataSchema** (`GraphDataSchema.cs`)
|
|||
|
|
定义 Canvas 节点字段 ↔ Excel 列的映射关系
|
|||
|
|
|
|||
|
|
**使用方式:**
|
|||
|
|
```
|
|||
|
|
在 Unity Editor 中:
|
|||
|
|
1. 右键 → Create → GameplayEditor/GraphDataSchema
|
|||
|
|
2. 配置字段映射:
|
|||
|
|
- fieldName: 节点中的字段名(支持嵌套如 'task.duration')
|
|||
|
|
- excelColumnName: Excel 表格列名
|
|||
|
|
- fieldType: 数据类型(String/Int/Float/Bool/Vector3/Color)
|
|||
|
|
3. 指定 sheetName(对应 Excel 中的 Sheet 名称)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**示例配置:**
|
|||
|
|
```
|
|||
|
|
Sheet: "技能"
|
|||
|
|
字段映射:
|
|||
|
|
- ID → NodeID (Int)
|
|||
|
|
- name → NodeName (String)
|
|||
|
|
- comment → 描述 (String)
|
|||
|
|
- task.duration → 持续时间 (Float)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2. **ExcelDataProvider** (`ExcelDataProvider.cs`)
|
|||
|
|
负责读写 .xlsx 文件的底层操作
|
|||
|
|
|
|||
|
|
**依赖:** EPPlus NuGet 包
|
|||
|
|
```bash
|
|||
|
|
# 在 Unity 项目中安装(需要配置 NuGet)
|
|||
|
|
Install-Package EPPlus
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**API:**
|
|||
|
|
```csharp
|
|||
|
|
var provider = new ExcelDataProvider("Assets/玩法编辑器.xlsx");
|
|||
|
|
|
|||
|
|
// 读取 Sheet
|
|||
|
|
var data = provider.ReadSheet("技能");
|
|||
|
|
|
|||
|
|
// 写入 Sheet
|
|||
|
|
provider.WriteSheet("技能", nodeDataList);
|
|||
|
|
|
|||
|
|
// 获取所有 Sheet 名称
|
|||
|
|
var sheets = provider.GetSheetNames();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3. **GraphExcelSyncManager** (`GraphExcelSyncManager.cs`)
|
|||
|
|
运行时双向同步管理器
|
|||
|
|
|
|||
|
|
**工作流程:**
|
|||
|
|
|
|||
|
|
**Canvas → Excel(自动):**
|
|||
|
|
```
|
|||
|
|
Graph.SelfSerialize()
|
|||
|
|
↓ (触发 onGraphSerialized 事件)
|
|||
|
|
↓
|
|||
|
|
GraphExcelSyncManager.OnGraphChanged()
|
|||
|
|
↓
|
|||
|
|
ExtractNodeData() (遍历所有节点,按 Schema 提取字段)
|
|||
|
|
↓
|
|||
|
|
ExcelDataProvider.WriteSheet() (写入 Excel)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Excel → Canvas(手动触发):**
|
|||
|
|
```
|
|||
|
|
SyncExcelToGraph()
|
|||
|
|
↓
|
|||
|
|
ExcelDataProvider.ReadSheet() (读取 Excel 数据)
|
|||
|
|
↓
|
|||
|
|
ApplyDataToGraph() (按 NodeID 匹配节点,更新字段)
|
|||
|
|
↓
|
|||
|
|
Graph 节点更新完成
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 4. **GameplayEditorWindow** (`GameplayEditorWindow.cs`)
|
|||
|
|
编辑器窗口 UI
|
|||
|
|
|
|||
|
|
**打开方式:** `Window → Gameplay Editor`
|
|||
|
|
|
|||
|
|
**功能:**
|
|||
|
|
- 左侧:Canvas 节点列表(实时显示)
|
|||
|
|
- 右侧:Schema 字段映射(配置参考)
|
|||
|
|
- 工具栏:同步按钮(Canvas ↔ Excel)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 使用流程
|
|||
|
|
|
|||
|
|
### 第一步:创建 Schema 配置
|
|||
|
|
```
|
|||
|
|
1. 在 Assets 中右键 → Create → GameplayEditor/GraphDataSchema
|
|||
|
|
2. 命名为 "SkillGraphSchema"
|
|||
|
|
3. 配置字段映射(对应你的 Graph 节点结构)
|
|||
|
|
4. 保存
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 第二步:配置 SyncManager
|
|||
|
|
```csharp
|
|||
|
|
// 在某个 MonoBehaviour 中
|
|||
|
|
public class GameplayController : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
public Graph skillGraph;
|
|||
|
|
public GraphDataSchema skillSchema;
|
|||
|
|
|
|||
|
|
private void Start()
|
|||
|
|
{
|
|||
|
|
var syncManager = gameObject.AddComponent<GraphExcelSyncManager>();
|
|||
|
|
syncManager.targetGraph = skillGraph;
|
|||
|
|
syncManager.schema = skillSchema;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 第三步:编辑工作流
|
|||
|
|
```
|
|||
|
|
1. 在 Canvas 中编辑节点 → 自动同步到 Excel
|
|||
|
|
2. 在 Excel 中修改数据 → 点击"同步 Excel → Canvas"更新
|
|||
|
|
3. 支持批量编辑:在 Excel 中修改多行数据,一次性导入
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 数据流向示例
|
|||
|
|
|
|||
|
|
### 场景:编辑技能节点
|
|||
|
|
|
|||
|
|
**Canvas 中的节点结构:**
|
|||
|
|
```csharp
|
|||
|
|
public class SkillNode : FlowNode
|
|||
|
|
{
|
|||
|
|
public int skillID;
|
|||
|
|
public string skillName;
|
|||
|
|
public float cooldown;
|
|||
|
|
public int manaCost;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Schema 配置:**
|
|||
|
|
```
|
|||
|
|
Sheet: "技能"
|
|||
|
|
字段映射:
|
|||
|
|
- skillID → 技能ID (Int)
|
|||
|
|
- skillName → 技能名称 (String)
|
|||
|
|
- cooldown → 冷却时间 (Float)
|
|||
|
|
- manaCost → 魔法消耗 (Int)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Excel 表格:**
|
|||
|
|
```
|
|||
|
|
| 技能ID | 技能名称 | 冷却时间 | 魔法消耗 |
|
|||
|
|
|--------|---------|---------|---------|
|
|||
|
|
| 1 | 火球术 | 5.0 | 50 |
|
|||
|
|
| 2 | 冰冻术 | 8.0 | 60 |
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**同步流程:**
|
|||
|
|
```
|
|||
|
|
修改 Canvas 节点 → Graph.SelfSerialize()
|
|||
|
|
→ onGraphSerialized 事件触发
|
|||
|
|
→ ExtractNodeData() 提取 [skillID, skillName, cooldown, manaCost]
|
|||
|
|
→ WriteSheet() 写入 Excel
|
|||
|
|
→ Excel 自动更新
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 高级特性
|
|||
|
|
|
|||
|
|
### 1. 节点类型过滤
|
|||
|
|
```csharp
|
|||
|
|
schema.nodeTypeFilter = new List<string> { "SkillNode", "BuffNode" };
|
|||
|
|
// 只同步这两种类型的节点
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 嵌套字段支持
|
|||
|
|
```csharp
|
|||
|
|
// 节点中有嵌套对象
|
|||
|
|
public class SkillNode : FlowNode
|
|||
|
|
{
|
|||
|
|
public SkillData data;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public class SkillData
|
|||
|
|
{
|
|||
|
|
public float duration;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Schema 配置支持嵌套路径
|
|||
|
|
fieldName = "data.duration"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 自定义字段类型转换
|
|||
|
|
```csharp
|
|||
|
|
// 在 ExcelDataProvider 中扩展
|
|||
|
|
private object ConvertValue(object value, GraphDataSchema.FieldType type)
|
|||
|
|
{
|
|||
|
|
switch (type)
|
|||
|
|
{
|
|||
|
|
case GraphDataSchema.FieldType.Vector3:
|
|||
|
|
// 自定义 Vector3 解析逻辑
|
|||
|
|
break;
|
|||
|
|
// ...
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 集成现有项目的步骤
|
|||
|
|
|
|||
|
|
### 1. 复制文件到项目
|
|||
|
|
```
|
|||
|
|
Assets/BP_Scripts/GameplayEditor/
|
|||
|
|
├── GraphDataSchema.cs
|
|||
|
|
├── ExcelDataProvider.cs
|
|||
|
|
├── GraphExcelSyncManager.cs
|
|||
|
|
└── GameplayEditorWindow.cs
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 安装 EPPlus 依赖
|
|||
|
|
```
|
|||
|
|
在 Packages/manifest.json 中添加:
|
|||
|
|
"com.epplus": "https://github.com/EPPlusSoftware/EPPlus.git"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 为现有 Graph 创建 Schema
|
|||
|
|
```
|
|||
|
|
对于每个 Graph 类型(技能、关卡、单位、行为树),
|
|||
|
|
创建对应的 Schema 配置文件
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. 启用自动同步
|
|||
|
|
```csharp
|
|||
|
|
// 在 GameplayController 中
|
|||
|
|
private void OnEnable()
|
|||
|
|
{
|
|||
|
|
Graph.onGraphSerialized += OnGraphChanged;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 与参考项目的对应关系
|
|||
|
|
|
|||
|
|
| 参考项目文件 | 我们的实现 | 用途 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| `行为树教程.xlsx` | `GraphDataSchema` | 定义表格结构 |
|
|||
|
|
| `x效果C054.xlsm` | `ExcelDataProvider` | 读写 Excel |
|
|||
|
|
| `g关卡C036.xlsm` | `GameplayEditorWindow` | 编辑界面 |
|
|||
|
|
| `d单位G071.xlsm` | `GraphExcelSyncManager` | 数据同步 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 故障排查
|
|||
|
|
|
|||
|
|
### 问题 1:Excel 文件被锁定
|
|||
|
|
**原因:** 文件被其他程序打开
|
|||
|
|
**解决:** 关闭 Excel,重新同步
|
|||
|
|
|
|||
|
|
### 问题 2:字段映射不生效
|
|||
|
|
**原因:** fieldName 拼写错误或字段不存在
|
|||
|
|
**解决:** 检查 Schema 配置中的 fieldName 是否与节点字段名完全匹配
|
|||
|
|
|
|||
|
|
### 问题 3:数据类型转换失败
|
|||
|
|
**原因:** Excel 中的数据类型与 Schema 定义不符
|
|||
|
|
**解决:** 在 ExcelDataProvider 中添加类型转换逻辑
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 扩展方向
|
|||
|
|
|
|||
|
|
1. **支持多 Graph 同时编辑** → 在 GameplayEditorWindow 中添加 Tab 页
|
|||
|
|
2. **版本控制** → 记录每次同步的时间戳和变更内容
|
|||
|
|
3. **冲突解决** → 当 Canvas 和 Excel 同时修改时的合并策略
|
|||
|
|
4. **导出配置** → 将 Graph 导出为 JSON/Protobuf 供游戏运行时使用
|
|||
|
|
5. **可视化表格** → 在 Editor 中直接显示 Excel 表格,支持拖拽编辑
|
|||
|
|
|