可视化方案
什么是Unity的可视化方案
很多,直接举例一些。
通用型
github开源:
- Node_Editor_Framework
- xNode
特化型
行为树
- NodeCanvas
- Behavior Designer
状态机
- FlowCanvas
- Bolt
- PlayerMaker
行为树编辑器有什么作用
- 剧情(对话)编辑
- AI编辑
- 技能编辑
- 碰撞关系编辑(纯数据,技能和单位是否可以碰撞)
- 装备合成路径编辑
- 其他
优劣
- 批量配置并不如Excel方便。
- 非常适合配合树状结构的数据。
思考
实现Excel和可视化编辑器之间的相互转化,会方便很多。
下面只进行odin的使用,不再对行为树、状态机一类的可视化插件进行关注。
原生编辑器
精灵、List、字典
show.cs
1 2 3 4 5 6 7 8 9
| public class Show : MonoBehaviour { public Sprite m_OriginSprite;
public List<int> m_OriginList = new List<int>();
public Dictionary<int, int> m_OriginDic = new Dictionary<int, int>(); }
|
Show_EditorExtension.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| [CustomEditor(typeof(Show))] public class Show_EditorExtension : Editor { public override void OnInspectorGUI() { Show show = (Show) target; show.m_OriginSprite = EditorGUILayout.ObjectField("这是一个精灵", show.m_OriginSprite, typeof(Sprite), true) as Sprite;
if (GUILayout.Button("这是一个按钮",GUILayout.Width(200))) { Debug.Log("点击了按钮"); } } }
|
Odin插件
精灵、List、字典
Show_EditorExtensionBasedOnOdin.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Show_EditorExtensionBasedOnOdin : SerializedMonoBehaviour { [PreviewField] [LabelText("这是一个精灵")] public Sprite m_OriginSprite;
public List<int> m_OriginList = new List<int>();
[LabelText("这是一个字典")] public Dictionary<int, int> m_OriginDic = new Dictionary<int, int>();
[Button("这是一个按钮", 30), GUIColor(0.7f, 0.3f, 1.0f)] public void TestButton() { Debug.Log("点击了按钮。"); } }
|
简单实现Window
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class MyHybridEditorWindowOne : OdinEditorWindow { [MenuItem("My Game/My Hybrid Editor")] private static void OpenWindow() { GetWindow<MyHybridEditorWindowOne>().Show(); }
[EnumToggleButtons, BoxGroup("Settings")] public ScaleMode ScaleMode;
[FolderPath(RequireExistingPath = true), BoxGroup("Settings")] public string OutputPath;
[HorizontalGroup(0.5f)] public List<Texture> InputTextures;
[HorizontalGroup, InlineEditor(InlineEditorModes.LargePreview)] public Texture Preview;
[Button(ButtonSizes.Gigantic), GUIColor(0, 1, 0)] public void PerformSomeAction() {
} }
|
- 继承OdinMenuEditorWindow
- 使用OdinMenuTree中的
Add
和AddAllAssetsAtPath
函数添加菜单。
Add: 设置菜单名称并传入对应需要渲染的类
AddAllAssetsAtPath:设置菜单名称,传入路径,示例中的第一个bool是指是否包含子路径,第二bool表示是否子路径的所有可用类都在一个层级中渲染,也就是要不要分Menu子选项。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class MyMenuEditorWindow : OdinMenuEditorWindow { [MenuItem("My Game/My Menu Editor")] private static void OpenWindow() { GetWindow<MyMenuEditorWindow>().Show(); }
protected override OdinMenuTree BuildMenuTree() { var tree = new OdinMenuTree(); tree.Selection.SupportsMultiSelect = false;
tree.Add("Settings", GeneralDrawerConfig.Instance); tree.Add("Utilities", new TextureUtilityEditor()); tree.AddAllAssetsAtPath("Odin Settings", "Assets/Plugins/Sirenix", typeof(ScriptableObject), true, true); return tree; } }
public class TextureUtilityEditor { [BoxGroup("Tool"), HideLabel, EnumToggleButtons] public Tool Tool;
public List<Texture> Textures;
[Button(ButtonSizes.Large), HideIf("Tool", Tool.Rotate)] public void SomeAction() { }
[Button(ButtonSizes.Large), ShowIf("Tool", Tool.Rotate)] public void SomeOtherAction() { } }
|
xNode插件
图
结点
odin与luban(导表工具)结合
工作流
luban 生成编辑器专用类型代码 => 编辑器中制作生成原始数据 json(编译器读存专用) => luban 处理json,导出成 运行时用的bytes 或 运行时用的json => 程序使用。
也就是说,每一个Cfg类型,如果想要在编辑器中调试,需要额外准备一套类型代码(继承自 EditorBeanBase,luban可以生成),与运行时中使用的类型相同。
- 写[xml/excel]定义数据类型
- [xml/excel]生成Editor专用class类型,对其代码进行标签处理(odin在这里派上用场,美化编辑器页面)
- ——————————-以下为需要重复的操作——————————-
- 使用Editor生成json数据 / 使用Editor读取json文件
- json数据 + [xml/excel] 生成bytes数据
- bytes数据作为运行时配置
demo
这一套工作流,我已经写成了一个简单的示例。
开源地址:https://github.com/CodingCodingK/odin_study
在这里感谢一下luban作者!教了我很多关于工作流搭建的思路和为什么这么做。
手册收藏
方便自己写的时候查询。
非常全面的中文教程
odin官方手册