可视化方案

什么是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)]//占比0.5
public List<Texture> InputTextures;

[HorizontalGroup, InlineEditor(InlineEditorModes.LargePreview)]
public Texture Preview;

[Button(ButtonSizes.Gigantic), GUIColor(0, 1, 0)]
public void PerformSomeAction()
{

}
}

简单实现Menu

  1. 继承OdinMenuEditorWindow
  2. 使用OdinMenuTree中的AddAddAllAssetsAtPath函数添加菜单。

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可以生成),与运行时中使用的类型相同。

  1. 写[xml/excel]定义数据类型
  2. [xml/excel]生成Editor专用class类型,对其代码进行标签处理(odin在这里派上用场,美化编辑器页面)
  3. ——————————-以下为需要重复的操作——————————-
  4. 使用Editor生成json数据 / 使用Editor读取json文件
  5. json数据 + [xml/excel] 生成bytes数据
  6. bytes数据作为运行时配置

demo

这一套工作流,我已经写成了一个简单的示例。

开源地址:https://github.com/CodingCodingK/odin_study

在这里感谢一下luban作者!教了我很多关于工作流搭建的思路和为什么这么做。

手册收藏

方便自己写的时候查询。

非常全面的中文教程

odin官方手册