diff --git a/Assets/ActivityGraph.asset b/Assets/ActivityGraph.asset
new file mode 100644
index 0000000..34df036
--- /dev/null
+++ b/Assets/ActivityGraph.asset
@@ -0,0 +1,24 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: b8409462a7f3e4d46a886d68e7626d94, type: 3}
+ m_Name: ActivityGraph
+ m_EditorClassIdentifier:
+ _serializedGraph: '{"type":"GameplayEditor.Core.GameplayGraph","nodes":[{"levelID":1,"nodeID":1,"nodeLayer":1,"eventTypeGroup":"1","priorityWeight":"1","eventMappingID":1,"_position":{"x":660.0},"$type":"GameplayEditor.Core.GameplayNode"}],"connections":[],"canvasGroups":[],"localBlackboard":{"_variables":{}}}'
+ _objectReferences: []
+ _graphSource:
+ _version: 3.33
+ _category:
+ _comments:
+ _translation: {x: -281, y: 182}
+ _zoomFactor: 1
+ _haltSerialization: 0
+ _externalSerializationFile: {fileID: 0}
diff --git a/Assets/ActivityGraph.asset.meta b/Assets/ActivityGraph.asset.meta
new file mode 100644
index 0000000..8763454
--- /dev/null
+++ b/Assets/ActivityGraph.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: a0bc0a969202f49498e8d63e4da11d62
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/BP_Scripts/BT_test.asset b/Assets/BP_Scripts/BT_test.asset
index d526cb6..be471f1 100644
--- a/Assets/BP_Scripts/BT_test.asset
+++ b/Assets/BP_Scripts/BT_test.asset
@@ -13,8 +13,8 @@ MonoBehaviour:
m_Name: BT_test
m_EditorClassIdentifier:
_serializedGraph: '{"type":"NodeCanvas.BehaviourTrees.BehaviourTree","nodes":[{"dynamic":true,"_tag":"\u521d\u59cb\u5316","_position":{"x":560.0,"y":280.0},"_comment":"\u8fd9\u662f\u5173\u5361\u521d\u59cb\u5316\uff0c\u5173\u5361\u5f00\u59cb\u5fc5\u6709","$type":"NodeCanvas.BehaviourTrees.Sequencer","$id":"0"},{"dynamic":true,"_position":{"x":420.0,"y":420.0},"$type":"NodeCanvas.BehaviourTrees.Sequencer","$id":"1"},{"_action":{"actions":[{"dictionary":{"_name":"Dictionary","_targetVariableID":"34aa1bb3-2cc8-4d06-9fb0-9d751d56ba17"},"key":{"_value":"1"},"value":{},"$type":"NodeCanvas.Tasks.Actions.AddElementToDictionary`1[[UnityEngine.Camera,
- UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]"},{"parent":{},"clonePosition":{},"cloneRotation":{},"saveCloneAs":{"_name":""},"$type":"NodeCanvas.Tasks.Actions.InstantiateGameObject"}],"$type":"NodeCanvas.Framework.ActionList"},"_position":{"x":120.0,"y":540.0},"_comment":"\u6dfb\u52a0\u76f8\u673a\u5230\u5217\u8868","$type":"NodeCanvas.BehaviourTrees.ActionNode","$id":"2"},{"_action":{"dictionary":{"_name":"Dictionary","_targetVariableID":"34aa1bb3-2cc8-4d06-9fb0-9d751d56ba17"},"key":{"_value":"1"},"saveAs":{"_name":"Main","_targetVariableID":"dc6ba0ab-ee9b-4bac-b4a9-8084a2f509b0"},"$type":"NodeCanvas.Tasks.Actions.GetDictionaryElement`1[[UnityEngine.Camera,
- UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]"},"_position":{"x":320.0,"y":540.0},"_comment":"\u4ece\u5217\u8868\u62ff\u76f8\u673a","$type":"NodeCanvas.BehaviourTrees.ActionNode","$id":"3"},{"dynamic":true,"_position":{"x":560.0,"y":420.0},"$type":"NodeCanvas.BehaviourTrees.Selector","$id":"4"},{"_position":{"x":700.0,"y":420.0},"$type":"NodeCanvas.BehaviourTrees.Parallel","$id":"5"},{"_position":{"x":700.0,"y":540.0},"$type":"NodeCanvas.BehaviourTrees.ConditionNode"},{"dynamic":true,"desires":[{"considerations":[]},{"considerations":[]},{"considerations":[]}],"_position":{"x":1040.0,"y":280.0},"$type":"NodeCanvas.BehaviourTrees.PrioritySelector","$version":1,"$id":"7"},{"_position":{"x":900.0,"y":420.0},"$type":"NodeCanvas.BehaviourTrees.ActionNode","$id":"8"},{"_position":{"x":1040.0,"y":420.0},"$type":"NodeCanvas.BehaviourTrees.ActionNode","$id":"9"},{"_position":{"x":1180.0,"y":420.0},"$type":"NodeCanvas.BehaviourTrees.ActionNode","$id":"10"},{"_position":{"x":560.0,"y":540.0},"$type":"NodeCanvas.BehaviourTrees.ActionNode"},{"_condition":{"conditions":[{"valueA":{"_name":""},"valueB":{},"$type":"NodeCanvas.Tasks.Conditions.CheckInt"},{"valueA":{"_name":"Dictionary","_targetVariableID":"34aa1bb3-2cc8-4d06-9fb0-9d751d56ba17"},"valueB":{"_value":{"":null}},"$type":"NodeCanvas.Tasks.Conditions.CheckVariable`1[[System.Collections.Generic.Dictionary`2[[System.String,
+ UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]"},{"parent":{},"clonePosition":{},"cloneRotation":{},"saveCloneAs":{"_name":""},"$type":"NodeCanvas.Tasks.Actions.InstantiateGameObject"}],"$type":"NodeCanvas.Framework.ActionList"},"_position":{"x":31.53383,"y":683.4225},"_comment":"\u6dfb\u52a0\u76f8\u673a\u5230\u5217\u8868","$type":"NodeCanvas.BehaviourTrees.ActionNode","$id":"2"},{"_action":{"dictionary":{"_name":"Dictionary","_targetVariableID":"34aa1bb3-2cc8-4d06-9fb0-9d751d56ba17"},"key":{"_value":"1"},"saveAs":{"_name":"Main","_targetVariableID":"dc6ba0ab-ee9b-4bac-b4a9-8084a2f509b0"},"$type":"NodeCanvas.Tasks.Actions.GetDictionaryElement`1[[UnityEngine.Camera,
+ UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]"},"_position":{"x":388.3602,"y":604.3391},"_comment":"\u4ece\u5217\u8868\u62ff\u76f8\u673a","$type":"NodeCanvas.BehaviourTrees.ActionNode","$id":"3"},{"dynamic":true,"_position":{"x":560.0,"y":420.0},"$type":"NodeCanvas.BehaviourTrees.Selector","$id":"4"},{"_position":{"x":700.0,"y":420.0},"$type":"NodeCanvas.BehaviourTrees.Parallel","$id":"5"},{"_position":{"x":700.0,"y":540.0},"$type":"NodeCanvas.BehaviourTrees.ConditionNode"},{"dynamic":true,"desires":[{"considerations":[]},{"considerations":[]},{"considerations":[]}],"_position":{"x":1040.0,"y":280.0},"$type":"NodeCanvas.BehaviourTrees.PrioritySelector","$version":1,"$id":"7"},{"_position":{"x":900.0,"y":420.0},"$type":"NodeCanvas.BehaviourTrees.ActionNode","$id":"8"},{"_position":{"x":1040.0,"y":420.0},"$type":"NodeCanvas.BehaviourTrees.ActionNode","$id":"9"},{"_position":{"x":1180.0,"y":420.0},"$type":"NodeCanvas.BehaviourTrees.ActionNode","$id":"10"},{"_position":{"x":560.0,"y":540.0},"$type":"NodeCanvas.BehaviourTrees.ActionNode"},{"_condition":{"conditions":[{"valueA":{"_name":""},"valueB":{},"$type":"NodeCanvas.Tasks.Conditions.CheckInt"},{"valueA":{"_name":"Dictionary","_targetVariableID":"34aa1bb3-2cc8-4d06-9fb0-9d751d56ba17"},"valueB":{"_value":{"":null}},"$type":"NodeCanvas.Tasks.Conditions.CheckVariable`1[[System.Collections.Generic.Dictionary`2[[System.String,
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[UnityEngine.Camera,
UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]],
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"}],"$type":"NodeCanvas.Framework.ConditionList"},"_position":{"x":480.0,"y":760.0},"$type":"NodeCanvas.BehaviourTrees.ConditionNode"}],"connections":[{"_sourceNode":{"$ref":"0"},"_targetNode":{"$ref":"1"},"$type":"NodeCanvas.BehaviourTrees.BTConnection"},{"_sourceNode":{"$ref":"0"},"_targetNode":{"$ref":"4"},"$type":"NodeCanvas.BehaviourTrees.BTConnection"},{"_sourceNode":{"$ref":"0"},"_targetNode":{"$ref":"5"},"$type":"NodeCanvas.BehaviourTrees.BTConnection"},{"_sourceNode":{"$ref":"1"},"_targetNode":{"$ref":"2"},"$type":"NodeCanvas.BehaviourTrees.BTConnection"},{"_sourceNode":{"$ref":"1"},"_targetNode":{"$ref":"3"},"$type":"NodeCanvas.BehaviourTrees.BTConnection"},{"_sourceNode":{"$ref":"7","$version":1},"_targetNode":{"$ref":"8"},"$type":"NodeCanvas.BehaviourTrees.BTConnection"},{"_sourceNode":{"$ref":"7","$version":1},"_targetNode":{"$ref":"9"},"$type":"NodeCanvas.BehaviourTrees.BTConnection"},{"_sourceNode":{"$ref":"7","$version":1},"_targetNode":{"$ref":"10"},"$type":"NodeCanvas.BehaviourTrees.BTConnection"}],"canvasGroups":[],"localBlackboard":{"_variables":{"myBoolean":{"_name":"myBoolean","_id":"597a5d7c-3bd9-4688-839b-d14d91ff6172","$type":"NodeCanvas.Framework.Variable`1[[System.Boolean,
@@ -28,7 +28,7 @@ MonoBehaviour:
_version: 3.33
_category:
_comments:
- _translation: {x: -8, y: 216}
- _zoomFactor: 1
+ _translation: {x: 275, y: -62}
+ _zoomFactor: 0.59610087
_haltSerialization: 0
_externalSerializationFile: {fileID: 0}
diff --git a/Assets/BP_Scripts/GameplayEditor/Core/ActivityNodeBase.cs.meta b/Assets/BP_Scripts/GameplayEditor/Core/ActivityNodeBase.cs.meta
new file mode 100644
index 0000000..51a0940
--- /dev/null
+++ b/Assets/BP_Scripts/GameplayEditor/Core/ActivityNodeBase.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7d04cbc7dec380c4a80a1cf00bcab601
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/BP_Scripts/GameplayEditor/Core/ActivityStageNode.cs.meta b/Assets/BP_Scripts/GameplayEditor/Core/ActivityStageNode.cs.meta
new file mode 100644
index 0000000..2cdc2a0
--- /dev/null
+++ b/Assets/BP_Scripts/GameplayEditor/Core/ActivityStageNode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e498e185f67a544479d637626a1f98a7
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/BP_Scripts/GameplayEditor/Core/BehaviourDocNodes.cs.meta b/Assets/BP_Scripts/GameplayEditor/Core/BehaviourDocNodes.cs.meta
new file mode 100644
index 0000000..8328052
--- /dev/null
+++ b/Assets/BP_Scripts/GameplayEditor/Core/BehaviourDocNodes.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f68ed535e8fe19d43ba9ae227e07c76d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/BP_Scripts/GameplayEditor/Core/BehaviourGraph.cs b/Assets/BP_Scripts/GameplayEditor/Core/BehaviourGraph.cs
new file mode 100644
index 0000000..245b610
--- /dev/null
+++ b/Assets/BP_Scripts/GameplayEditor/Core/BehaviourGraph.cs
@@ -0,0 +1,49 @@
+using NodeCanvas.BehaviourTrees;
+using ParadoxNotion;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace GameplayEditor.Core
+{
+ ///
+ /// 行为树 Graph - 支持可执行的行为逻辑 + 表格编辑
+ /// 继承 BehaviourTree,额外支持 ActivityNodeBase 节点的导出/导入
+ ///
+ [System.Serializable]
+ [CreateAssetMenu(menuName = "NodeCanvas/Behaviour Graph")]
+ public class BehaviourGraph : BehaviourTree
+ {
+ public void ExportToExcel(string path)
+ {
+ Export.ExcelExporter.Export(this, path);
+ }
+
+ public void ImportFromExcel(string path)
+ {
+ Export.ExcelImporter.Import(path, this);
+ }
+
+ public List GetNodesByType() where T : Node
+ {
+ return allNodes.OfType().ToList();
+ }
+
+ public List GetAllActivityNodes()
+ {
+ return allNodes.OfType().ToList();
+ }
+
+ public Dictionary> GetNodesByTableName()
+ {
+ var result = new Dictionary>();
+ foreach (var node in GetAllActivityNodes())
+ {
+ if (!result.ContainsKey(node.TableName))
+ result[node.TableName] = new List();
+ result[node.TableName].Add(node);
+ }
+ return result;
+ }
+ }
+}
diff --git a/Assets/BP_Scripts/GameplayEditor/Core/DataNodes.cs.meta b/Assets/BP_Scripts/GameplayEditor/Core/DataNodes.cs.meta
new file mode 100644
index 0000000..0a3c56e
--- /dev/null
+++ b/Assets/BP_Scripts/GameplayEditor/Core/DataNodes.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 25cde69a219386b44bccc0c08271bdc2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/BP_Scripts/GameplayEditor/Core/LutNodes.cs.meta b/Assets/BP_Scripts/GameplayEditor/Core/LutNodes.cs.meta
new file mode 100644
index 0000000..3b9ab6c
--- /dev/null
+++ b/Assets/BP_Scripts/GameplayEditor/Core/LutNodes.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 758081b0b34f2e942b68f9fa35170ba8
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/BP_Scripts/GameplayEditor/Export/ExcelExporter.cs b/Assets/BP_Scripts/GameplayEditor/Export/ExcelExporter.cs
index f0bdeda..28584d6 100644
--- a/Assets/BP_Scripts/GameplayEditor/Export/ExcelExporter.cs
+++ b/Assets/BP_Scripts/GameplayEditor/Export/ExcelExporter.cs
@@ -3,28 +3,41 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using GameplayEditor.Core;
+using NodeCanvas.Framework;
using UnityEngine;
namespace GameplayEditor.Export
{
public static class ExcelExporter
{
- public static void Export(GameplayGraph graph, string basePath)
+ public static void Export(Graph graph, string basePath)
{
- var nodesByTable = graph.GetNodesByTableName();
+ var activityNodes = graph.allNodes.OfType().ToList();
+ if (activityNodes.Count == 0)
+ {
+ Debug.LogWarning("No ActivityNodeBase nodes found in graph");
+ return;
+ }
+
+ var nodesByTable = new Dictionary>();
+ foreach (var node in activityNodes)
+ {
+ if (!nodesByTable.ContainsKey(node.TableName))
+ nodesByTable[node.TableName] = new List();
+ nodesByTable[node.TableName].Add(node);
+ }
foreach (var kvp in nodesByTable)
{
var tableName = kvp.Key;
var nodes = kvp.Value;
-
if (nodes.Count == 0) continue;
var excelPath = Path.Combine(Path.GetDirectoryName(basePath), $"{tableName}.csv");
ExportTable(nodes, excelPath);
}
- Debug.Log($"Exported {nodesByTable.Count} tables from {basePath}");
+ Debug.Log($"Exported {nodesByTable.Count} tables from graph");
}
private static void ExportTable(List nodes, string filePath)
diff --git a/Assets/BP_Scripts/GameplayEditor/Export/ExcelImporter.cs b/Assets/BP_Scripts/GameplayEditor/Export/ExcelImporter.cs
index 5b4fffc..cd3f064 100644
--- a/Assets/BP_Scripts/GameplayEditor/Export/ExcelImporter.cs
+++ b/Assets/BP_Scripts/GameplayEditor/Export/ExcelImporter.cs
@@ -25,13 +25,13 @@ namespace GameplayEditor.Export
{ "DialogInfo", () => new DialogInfoNode() },
};
- public static void Import(string filePath, GameplayGraph graph)
+ public static void Import(string filePath, Graph graph)
{
var tableName = Path.GetFileNameWithoutExtension(filePath);
ImportTable(filePath, graph, tableName);
}
- public static void ImportTable(string filePath, GameplayGraph graph, string tableName)
+ public static void ImportTable(string filePath, Graph graph, string tableName)
{
if (!File.Exists(filePath))
{
diff --git a/Assets/BP_Scripts/GameplayEditor/GameplayEditorWindow.cs b/Assets/BP_Scripts/GameplayEditor/GameplayEditorWindow.cs
index d23846a..9010a1c 100644
--- a/Assets/BP_Scripts/GameplayEditor/GameplayEditorWindow.cs
+++ b/Assets/BP_Scripts/GameplayEditor/GameplayEditorWindow.cs
@@ -68,15 +68,23 @@ namespace GameplayEditor
if (currentGraph == null)
{
- EditorGUILayout.HelpBox("请选择一个 Graph", MessageType.Info);
+ EditorGUILayout.HelpBox("请选择一个 Graph(GameplayGraph 或 BehaviourGraph)", MessageType.Info);
return;
}
canvasScroll = EditorGUILayout.BeginScrollView(canvasScroll);
- var nodesByTable = (currentGraph as Core.GameplayGraph)?.GetNodesByTableName();
- if (nodesByTable != null)
+ var activityNodes = currentGraph.allNodes.OfType().ToList();
+ if (activityNodes.Count > 0)
{
+ var nodesByTable = new Dictionary>();
+ foreach (var node in activityNodes)
+ {
+ if (!nodesByTable.ContainsKey(node.TableName))
+ nodesByTable[node.TableName] = new List();
+ nodesByTable[node.TableName].Add(node);
+ }
+
foreach (var kvp in nodesByTable.OrderBy(x => x.Key))
{
EditorGUILayout.LabelField($"{kvp.Key} ({kvp.Value.Count})", EditorStyles.boldLabel);
@@ -89,6 +97,10 @@ namespace GameplayEditor
}
}
}
+ else
+ {
+ EditorGUILayout.HelpBox("Canvas 中没有 ActivityNodeBase 节点", MessageType.Info);
+ }
EditorGUILayout.EndScrollView();
}
@@ -125,7 +137,7 @@ namespace GameplayEditor
}
var basePath = "Assets/玩法编辑器.csv";
- (currentGraph as Core.GameplayGraph)?.ExportToExcel(basePath);
+ Export.ExcelExporter.Export(currentGraph, basePath);
EditorUtility.DisplayDialog("成功", $"已导出所有表到 Assets/ 目录", "确定");
}
@@ -142,7 +154,7 @@ namespace GameplayEditor
{
var filePath = System.IO.Path.Combine(basePath, $"{tableName}.csv");
if (System.IO.File.Exists(filePath))
- Export.ExcelImporter.ImportTable(filePath, currentGraph as Core.GameplayGraph, tableName);
+ Export.ExcelImporter.ImportTable(filePath, currentGraph, tableName);
}
EditorUtility.DisplayDialog("成功", "已导入所有 CSV 表", "确定");
diff --git a/Assets/BehaviourTree.csv b/Assets/BehaviourTree.csv
new file mode 100644
index 0000000..ca50c0a
--- /dev/null
+++ b/Assets/BehaviourTree.csv
@@ -0,0 +1,4 @@
+LevelID,NodeID,NodeLayer,EventTypeGroup,Priority,EventMappingID,InteractVisible,NodeState,ParentNodeID
+int,int,int,string,string,int,bool,bool,int
+关卡编号ID,节点ID(唯一),节点层级,节点事件类型组(|分隔),优先级权重(|分隔),存储事件ID映射,交互是否可见,节点是否可进入,父节点ID(-1表示根节点)
+1,1,1,1,1,1,True,True,-1
diff --git a/Assets/BehaviourTree.csv.meta b/Assets/BehaviourTree.csv.meta
new file mode 100644
index 0000000..e58fa66
--- /dev/null
+++ b/Assets/BehaviourTree.csv.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 89e2f58b96cb09245a29a89b64f4239d
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/New Graph Data Schema.asset b/Assets/New Graph Data Schema.asset
new file mode 100644
index 0000000..aff94cc
--- /dev/null
+++ b/Assets/New Graph Data Schema.asset
@@ -0,0 +1,26 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fd283cf39e183a04d814b09c20b2a810, type: 3}
+ m_Name: New Graph Data Schema
+ m_EditorClassIdentifier:
+ sheetName: "\u6280\u80FD"
+ fields:
+ - fieldName: ID
+ excelColumnName: NodeID
+ fieldType: 1
+ - fieldName: name
+ excelColumnName: NodeName
+ fieldType: 0
+ - fieldName: comment
+ excelColumnName: "\u63CF\u8FF0"
+ fieldType: 0
+ nodeTypeFilter: []
diff --git a/Assets/New Graph Data Schema.asset.meta b/Assets/New Graph Data Schema.asset.meta
new file mode 100644
index 0000000..f1068bd
--- /dev/null
+++ b/Assets/New Graph Data Schema.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0de0e36ee42ae394a8ac5b18dc6303ed
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset
index 1aadda9..ee0c0c6 100644
--- a/ProjectSettings/ProjectSettings.asset
+++ b/ProjectSettings/ProjectSettings.asset
@@ -382,6 +382,103 @@ PlayerSettings:
m_Height: 36
m_Kind: 0
m_SubKind:
+ - m_BuildTarget: iPhone
+ m_Icons:
+ - m_Textures: []
+ m_Width: 180
+ m_Height: 180
+ m_Kind: 0
+ m_SubKind: iPhone
+ - m_Textures: []
+ m_Width: 120
+ m_Height: 120
+ m_Kind: 0
+ m_SubKind: iPhone
+ - m_Textures: []
+ m_Width: 167
+ m_Height: 167
+ m_Kind: 0
+ m_SubKind: iPad
+ - m_Textures: []
+ m_Width: 152
+ m_Height: 152
+ m_Kind: 0
+ m_SubKind: iPad
+ - m_Textures: []
+ m_Width: 76
+ m_Height: 76
+ m_Kind: 0
+ m_SubKind: iPad
+ - m_Textures: []
+ m_Width: 120
+ m_Height: 120
+ m_Kind: 3
+ m_SubKind: iPhone
+ - m_Textures: []
+ m_Width: 80
+ m_Height: 80
+ m_Kind: 3
+ m_SubKind: iPhone
+ - m_Textures: []
+ m_Width: 80
+ m_Height: 80
+ m_Kind: 3
+ m_SubKind: iPad
+ - m_Textures: []
+ m_Width: 40
+ m_Height: 40
+ m_Kind: 3
+ m_SubKind: iPad
+ - m_Textures: []
+ m_Width: 87
+ m_Height: 87
+ m_Kind: 1
+ m_SubKind: iPhone
+ - m_Textures: []
+ m_Width: 58
+ m_Height: 58
+ m_Kind: 1
+ m_SubKind: iPhone
+ - m_Textures: []
+ m_Width: 29
+ m_Height: 29
+ m_Kind: 1
+ m_SubKind: iPhone
+ - m_Textures: []
+ m_Width: 58
+ m_Height: 58
+ m_Kind: 1
+ m_SubKind: iPad
+ - m_Textures: []
+ m_Width: 29
+ m_Height: 29
+ m_Kind: 1
+ m_SubKind: iPad
+ - m_Textures: []
+ m_Width: 60
+ m_Height: 60
+ m_Kind: 2
+ m_SubKind: iPhone
+ - m_Textures: []
+ m_Width: 40
+ m_Height: 40
+ m_Kind: 2
+ m_SubKind: iPhone
+ - m_Textures: []
+ m_Width: 40
+ m_Height: 40
+ m_Kind: 2
+ m_SubKind: iPad
+ - m_Textures: []
+ m_Width: 20
+ m_Height: 20
+ m_Kind: 2
+ m_SubKind: iPad
+ - m_Textures: []
+ m_Width: 1024
+ m_Height: 1024
+ m_Kind: 4
+ m_SubKind: App Store
m_BuildTargetBatching:
- m_BuildTarget: WebGL
m_StaticBatching: 1
diff --git a/设计文档/玩法编辑器使用手册.md b/设计文档/玩法编辑器使用手册.md
index 331275d..cee30ae 100644
--- a/设计文档/玩法编辑器使用手册.md
+++ b/设计文档/玩法编辑器使用手册.md
@@ -177,92 +177,218 @@ UI 资源。填写需要使用的关卡和映射 ID,可以填 String。
```
Assets/BP_Scripts/GameplayEditor/
├── Core/
-│ ├── GameplayGraph.cs ← 自定义 Graph 类型(Asset 本体)
-│ ├── GameplayNode.cs ← 节点数据模型(含9个业务字段)
-│ └── GameplayConnection.cs ← 节点连线类型
+│ ├── ActivityNodeBase.cs ← 所有节点的抽象基类
+│ ├── GameplayNode.cs ← 行为树逻辑节点(工作表2)
+│ ├── ActivityStageNode.cs ← 关卡配置节点(工作表1)
+│ ├── BehaviourDocNodes.cs ← 节点说明 + 组合节点(工作表3/4)
+│ ├── LutNodes.cs ← UI/Camera/FX资源映射(3.2/3.3/3.4)
+│ ├── DataNodes.cs ← 地图/对话配置节点(3.5/3.6/3.7)
+│ ├── GameplayGraph.cs ← 自定义 Graph 类型
+│ └── GameplayConnection.cs ← 节点连线类型
├── Export/
-│ ├── ExcelExporter.cs ← Canvas → CSV 导出逻辑
-│ └── ExcelImporter.cs ← CSV → Canvas 导入逻辑
-├── GameplayEditorWindow.cs ← 编辑器窗口 UI
-├── GraphDataSchema.cs ← 字段映射配置(ScriptableObject)
-├── GraphExcelSyncManager.cs ← 运行时同步组件
-└── ExcelDataProvider.cs ← CSV 读写基础工具
+│ ├── ExcelExporter.cs ← Canvas → 多个 CSV 导出
+│ └── ExcelImporter.cs ← 多个 CSV → Canvas 导入
+├── GameplayEditorWindow.cs ← 编辑器窗口 UI(支持表格选择)
+├── GraphDataSchema.cs ← 字段映射配置(ScriptableObject)
+├── GraphExcelSyncManager.cs ← 运行时同步组件
+└── ExcelDataProvider.cs ← CSV 读写基础工具
```
---
-### 5.2 快速开始
+### 5.2 快速开始(完整流程)
**第一步:创建 GameplayGraph Asset**
-在 Project 窗口中右键 → **Create → NodeCanvas → Gameplay Graph**,命名为关卡名,例如 `Level01Graph`。
+在 Project 窗口中右键 → **Create → NodeCanvas → Gameplay Graph**,命名为 `ActivityGraph`。
-**第二步:创建 GraphDataSchema 配置**
-
-右键 → **Create → GameplayEditor → GraphDataSchema**,命名为 `Level01Schema`,在 Inspector 中可查看字段映射关系(用于编辑器窗口右侧展示)。
-
-**第三步:打开玩法编辑器窗口**
+**第二步:打开玩法编辑器窗口**
菜单栏 → **Window → Gameplay Editor**
```
┌──────────────────────────────────────────────────────────────┐
-│ [Graph 拖槽] [Schema 拖槽] [导出 Canvas→CSV] [导入 CSV→Canvas] │ ← 工具栏
+│ [Graph 拖槽] [Schema 拖槽] [导出所有表→CSV] [导入CSV→Canvas] │ ← 工具栏
├─────────────────────┬────────────────────────────────────────┤
-│ Canvas 可视化编辑 │ CSV 字段映射 │
-│ 显示所有节点列表 │ 显示 Schema 中配置的字段映射关系 │
+│ Canvas 节点列表 │ 表格选择 + 字段映射 │
+│ 按表格分组显示所有 │ 下拉菜单选择要查看的表格 │
+│ 节点(10种类型) │ 显示该表的字段结构 │
└─────────────────────┴────────────────────────────────────────┘
```
-将 `Level01Graph` 和 `Level01Schema` 分别拖入工具栏对应拖槽。
+将 `ActivityGraph` 拖入工具栏左侧的 **Graph 拖槽**。
-**第四步:在 Canvas 中编辑节点**
+**第三步:在 Canvas 中添加节点**
-双击 `Level01Graph.asset` 打开 NodeCanvas 编辑器,右键画布 → **Add Node → GameplayEditor → GameplayNode** 添加节点。
+双击 `ActivityGraph.asset` 打开 NodeCanvas 编辑器,右键画布 → **Add Node → GameplayEditor → [节点类型]**
-点击节点在 Inspector 中编辑以下字段:
+支持的节点类型(10种):
-| 字段名 | 类型 | 说明 |
-|-------------------|--------|---------------------------------------------------|
-| Level ID | int | 关卡编号 ID(对应 ActivityStageID) |
-| Node ID | int | 节点唯一 ID(**同一 Graph 内不能重复**) |
-| Node Layer | int | 节点层级(0 为顶层根节点) |
-| Event Type Group | string | 事件类型组,多个用 `\|` 分隔,如 `1\|2\|3` |
-| Priority | string | 优先级权重,多个用 `\|` 分隔,如 `10\|20` |
-| Event Mapping ID | int | 事件 ID 映射值(对应各 Lut 表中的映射 ID) |
-| Interact Visible | bool | 交互时是否显示该节点 |
-| Node State | bool | 节点是否处于可进入状态 |
-| Parent Node ID | int | 父节点的 Node ID,**-1 表示根节点(无父节点)** |
+| 节点类型 | 对应表格 | 用途 |
+|---------|---------|------|
+| GameplayNode | BehaviourTree | 行为树逻辑节点 |
+| ActivityStageNode | ActivityStage | 关卡配置(场景、地图、相机) |
+| BehaviourNodeDocNode | BehaviourNodeDoc | 节点类型说明(注释用) |
+| ActivityGroupNode | ActivityGroup | 组合节点说明 |
+| UiLutNode | ActivityUiLut | UI资源映射 |
+| CameraLutNode | ActivityCameraLut | 相机资源映射 |
+| FXLutNode | ActivityFXLut | 特效资源映射 |
+| MapInfoNode | ActivityMapInfoLut | 地图打点(支持8个点) |
+| DialogByStageNode | ActivityDialogInfoByStage | 对话索引 |
+| DialogInfoNode | DialogInfo | 对话详细配置 |
-拖拽节点端口建立连线,连线关系在导入时会根据 `ParentNodeID` 字段自动重建。
+**第四步:编辑节点字段**
-**第五步:导出 Canvas → CSV**
+点击节点在 Inspector 中填写对应字段。每种节点的字段不同,参考下方字段说明。
-工具栏点击 **"导出 Canvas → CSV"**,输出到 `Assets/玩法编辑器.csv`。
+**第五步:导出所有表 → CSV**
-生成格式(行1=字段名,行2=类型,行3=说明,行4起=节点数据):
+工具栏点击 **"导出所有表 → CSV"**,自动生成 10 个 CSV 文件到 `Assets/` 目录:
+
+```
+Assets/
+├── BehaviourTree.csv
+├── ActivityStage.csv
+├── BehaviourNodeDoc.csv
+├── ActivityGroup.csv
+├── ActivityUiLut.csv
+├── ActivityCameraLut.csv
+├── ActivityFXLut.csv
+├── ActivityMapInfoLut.csv
+├── ActivityDialogInfoByStage.csv
+└── DialogInfo.csv
+```
+
+每个 CSV 格式(行1=字段名,行2=类型,行3=说明,行4起=数据):
```
LevelID,NodeID,NodeLayer,EventTypeGroup,Priority,EventMappingID,InteractVisible,NodeState,ParentNodeID
int,int,int,string,string,int,bool,bool,int
-关卡编号ID,节点ID(唯一),节点层级,节点事件类型组(|分隔),优先级权重(|分隔),存储事件ID映射,交互是否可见,节点是否可进入,父节点ID(-1表示无父节点)
+关卡编号ID,节点ID(唯一),节点层级,节点事件类型组(|分隔),优先级权重(|分隔),存储事件ID映射,交互是否可见,节点是否可进入,父节点ID(-1表示根节点)
1,101,0,1|2,10|20,5001,True,True,-1
1,102,1,3,30,5002,True,True,101
```
-> 生成的 `.csv` 可直接用 Excel 打开(打开时选 UTF-8 编码)。
+**第六步:用 Excel 批量编辑**
-**第六步:批量编辑后导入 CSV → Canvas**
+1. 用 Excel 打开任意 CSV(打开时选 UTF-8 编码)
+2. 修改数据(**不要删除前3行表头**)
+3. 保存文件
-1. 用 Excel 修改 `Assets/玩法编辑器.csv`(**不要删除前3行表头**)
-2. 保存文件
-3. 回到 Unity,点击 **"导入 CSV → Canvas"**
+**第七步:导入 CSV → Canvas**
-> **注意:导入会清空当前 Canvas 中的所有节点后重建。** 导入后自动根据 `ParentNodeID` 重建连线,`-1` 表示根节点不连线。
+回到 Unity,点击 **"导入 CSV → Canvas"**
+
+> **注意:导入会清空当前 Canvas 中的所有节点后重建。** 导入后自动根据 `ParentNodeID` 重建 GameplayNode 连线。
---
-### 5.3 嵌套节点示例
+### 5.3 各表字段说明
+
+#### 工作表1:ActivityStage(关卡配置)
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| ActivityStageID | int | 行为树ID(全局唯一) |
+| Doc | string | 关卡备注 |
+| SceneName | string | 场景名称 |
+| MapInfo | string | 地图打点组ID |
+| CloseLoadingDelaySeconds | float | 关闭加载画面延迟(秒) |
+| CameraID | int | 默认相机ID |
+
+#### 工作表2:BehaviourTree(行为树逻辑)
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| LevelID | int | 关卡编号ID |
+| NodeID | int | 节点唯一ID(**同一Graph内不重复**) |
+| NodeLayer | int | 节点层级(0=顶层) |
+| EventTypeGroup | string | 事件类型组(`\|`分隔,如 `1\|2\|3`) |
+| Priority | string | 优先级权重(`\|`分隔,如 `10\|20`) |
+| EventMappingID | int | 事件ID映射值 |
+| InteractVisible | bool | 交互时是否显示 |
+| NodeState | bool | 节点是否可进入 |
+| ParentNodeID | int | 父节点ID(**-1=根节点**) |
+
+#### 工作表3:BehaviourNodeDoc(节点说明)
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| NodeType | string | 节点类型(如 DoGetTime) |
+| Description | string | 节点描述 |
+| ChineseMapping | string | 中文节点映射 |
+| Param1~5 | string | 参数1~5说明 |
+
+#### 工作表4:ActivityGroup(组合节点)
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| GroupTreeID | string | 组合树ID |
+| GroupTreeType | string | 组合树类型/节点名称 |
+| Comment | string | 注释 |
+
+#### 3.2:ActivityUiLut(UI资源映射)
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| StageID | int | 关卡ID |
+| UIMappingID | int | UI映射ID |
+| PrefabPath | string | Prefab路径 |
+
+#### 3.3:ActivityCameraLut(相机资源映射)
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| StageID | int | 关卡ID |
+| CamMappingID | int | 相机映射ID |
+| PrefabPath | string | Prefab路径 |
+
+#### 3.4:ActivityFXLut(特效资源映射)
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| StageID | int | 关卡ID |
+| FXMappingID | int | 特效映射ID |
+| PrefabPath | string | Prefab路径 |
+
+#### 3.5:ActivityMapInfoLut(地图打点)
+
+支持最多8个打点,每个打点包含 ID 和 Vector3 坐标(格式:`x\|y\|z`)
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| InfoID | int | 地图信息ID |
+| PointID_1~8 | string | 打点ID |
+| Coord_1~8 | Vector3 | 坐标(x\|y\|z) |
+
+#### 3.6:ActivityDialogInfoByStage(对话索引)
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| StageID | int | 玩法关卡ID |
+| DialogConfigTable | string | 对应文本配置表名称 |
+
+#### 3.7:DialogInfo(对话详细配置)
+
+行为树对应节点:`DoShowDialog(DialogInfoID)`
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| id | int | 配置ID |
+| isMask | bool | 是否开启蒙层 |
+| MaskTarget | string | 蒙层位置(万分比坐标 x,y) |
+| ClickKey | int | 关闭蒙层键值 |
+| DialogType | int | 战中类型 |
+| UIType | int | UI样式 |
+| PrefabPath | string | UI预制体路径(默认空) |
+| Name | string | 显示角色名 |
+| Text | string | 正文(支持富文本) |
+| Duration | float | 显示时间 |
+| Params1~5 | string | 特殊参数1~5 |
+
+---
+
+### 5.4 嵌套节点示例(仅 GameplayNode)
**CSV 数据:**
@@ -287,14 +413,14 @@ int,int,int,...,int
---
-### 5.4 运行时自动同步(可选)
+### 5.5 运行时自动同步(可选)
如需在运行时自动同步,将 `GraphExcelSyncManager` 组件挂到场景中的 GameObject 上:
1. **Add Component → GraphExcelSyncManager**
2. Inspector 中绑定 `Target Graph` 和 `Schema`
-之后每次 Graph 触发序列化事件时会自动写入 CSV。
+之后每�� Graph 触发序列化事件时会自动写入 CSV。
---
@@ -305,6 +431,8 @@ int,int,int,...,int
| 导入后节点全部重叠 | 导入时节点默认位置为 Vector2.zero | 在 Canvas 中手动排布节点位置 |
| CSV 用 Excel 打开乱码 | 编码不一致 | Excel → 数据 → 从文本/CSV 导入 → 选 UTF-8 |
| 导入报错 "CSV file format invalid" | 缺少前3行表头 | 保留 NAME/TYPE/DOC 三行,数据从第4行开始 |
-| 点击导出提示"请选择 Graph 和 Schema" | 工具栏拖槽为空 | Graph 和 Schema 两个拖槽都需要赋值 |
-| Create 菜单找不到 Gameplay Graph | 正常,菜单已注册 | 右键 → Create → NodeCanvas → Gameplay Graph |
-| QA 发现流程卡死 | 可能是配置问题也可能是程序问题 | 先策划自检行为树节点报错,确认非配置问题再提程序单 |
+| 点击导出提示"请选择 Graph" | Graph 拖槽为空 | Graph 拖槽必须赋值 |
+| 导入时提示"Unknown table name" | CSV 文件名不匹配 | 确保 CSV 文件名为标准表名(BehaviourTree.csv 等) |
+| 某个表导入失败 | 该表的 CSV 格式错误 | 检查前3行表头是否完整,数据行是否有缺失 |
+| 导出后找不到 CSV 文件 | 导出路径不对 | CSV 文件生成在 Assets/ 目录,刷新 Project 窗口 |
+| ParentNodeID 连线没有重建 | 只有 GameplayNode 支持嵌套 | 其他节点类型不支持父子关系 |