| 
        
        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 时间紧任务重 。 果然还是先快点完成比较好。