|
2024-04-05
|
# Unity 节点编辑器
前言: 狂怒传说 项目中 因为想要做一个泛用的对话树 对话树还要被大行为树包起来? 好好好 小小 NPC 必须好好捣鼓一下 这下好了 不得不手搓行为树了

image-20240405034841452
如何让 Assets 跟 Hierarchy 之间进行序列化的存储可难倒我了 这里 就要弄清楚 GameObject 在 Scene Assets 中的区别了
考虑到效率 我打算先临时用一个 Hash 值来 表示数据 Data
节点保存 int 的哈希值,然后每次选中节点的时候 根据哈希值和当前树的拥有者来通过 Linq 查找 List 集合中的数据 Data
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
|
using System; using System.Collections.Generic; using System.Reflection; using KooFrame; using UnityEngine; using UnityEngine.Events;
namespace SubSystem { [Serializable] public class NodeDataInOwner {
[SerializeField, HideInInspector] public List<string> methodsTypeNames = new();
[SerializeField] public UnityEvent Event = new UnityEvent();
[SerializeField] public string CurRegisterMethodName;
[SerializeField] public int OwnerDataID;
[SerializeField] public TreeOwner Owner;
[SerializeField] public GameObject EventTrigger;
[SerializeField] public Node BindNode;
public NodeDataInOwner(Node node, TreeOwner owner) { BindNode = node; Owner = owner; OwnerDataID = Animator.StringToHash(owner.name + (owner.NodeDatas.Count) .ToString()); }
public void EventAddListener(MethodInfo methodInfo, Type invokeObj) { UnityAction methodDelegate = () => methodInfo.Invoke( EventTrigger.GetComponent(invokeObj), null); CurRegisterMethodName = invokeObj.FullName + "/" + methodInfo.Name; Event.AddListener(methodDelegate); } } }
|
那么接下来一个问题就出现了 我序列化了要触发方法的名字 这里我如何通过名字拿到方法的委托来用来注册到事件里面去呢。
通过对象 和对象的 Component 名称 和当中的方法名称 在 OnEnable 的时候 反射拿到方法 并注册进事件当中
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
| private void OnEnable() { foreach (var nodeDataInOwner in NodeDatas) { string[] typeAndmethod = nodeDataInOwner.CurRegisterMethodName.Split("/", StringSplitOptions.None); Type type = nodeDataInOwner.EventTrigger.GetComponent(Type.GetType(typeAndmethod[0])).GetType(); MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance); MethodInfo method = null; foreach (var methodInfo in methods) { if (methodInfo.ReturnType == typeof(void) && methodInfo.GetParameters().Length == 0 && methodInfo.Name == typeAndmethod[1]) { method = methodInfo; } }
UnityAction action = () => { if (method != null) method.Invoke(nodeDataInOwner.EventTrigger.GetComponent(type), null); };
nodeDataInOwner.Event.AddListener(action); } }
|
这里的流程应该还能优化一些 让 OnEnable 可以执行的更快
0406
今天制作节点编辑器遇到了很多困难 比较触碰到了那个实验性的基类的属性 而且又是我知识盲区。
第一个是 节点没办法根据鼠标位置来创建
第一个完全是坐标系的转换很出问题 就仿佛是之前在 Scene 窗口 右键移动 GO 一样
转换不同坐标系是很麻烦的一件事
第二个则是 节点的复制和黏贴
这里则是 Node 的数据层没有很好的剥离开来。导致需要序列化的时候。 没办法转换成能方便复制黏贴的 json 格式。
这里我想只有两种解决办法
- 自己定义 string 化的格式和内容,只抽离出必要的数据。来完成复制和黏贴
- 新写出可序列化的数据类 NodeModel,复制的时候 json 化 Model 类 同理 黏贴的时候反序列化一下
不过我也在油管上找到了合适的教程 ,可是 demo 时间紧任务重 。 果然还是先快点完成比较好。