Unity Editor 基础篇(十一):结点编辑器基础

转自:http://mp.weixin.qq.com/s/CV_UTPMsWmz5w0gSOIPyFQ,请点击连接查看原文,尊重楼主版权。

 

前言:

本文主要讲解Unity编辑器中节点编辑器的创建使用。

 

知识点:

1.在自定义窗口内点击显示菜单项

使用GenericMenu(通用菜单):

注意:这是一个编辑器类,如果想使用它你需要把它放到工程目录下的Assets/Editor文件夹下。编辑器类在UnityEditor命名空间下。所以当使用C#脚本时,你需要在脚本前面加上 "using UnityEditor"引用。

函数:

AddIten:添加一个项目到菜单;

参数:function AddItem ( GUIContent 格式, on : boolean, 点击菜单项回调, 回调的参数) : void

其中第二个参数控制如下显示:

AddDisabledItem:添加一个禁用项目到菜单;

AddSeparator:添加一个分隔条项目到菜单;

GetItemCount:获取菜单中的项目数;

ShowAsContext: 显示鼠标下方的菜单;

DropDown:在给定屏幕矩形位置显示菜单。

 

  1. GenericMenu menu = new GenericMenu();

  2. menu.AddItem(new GUIContent("Add Input"), false, MenuCallback, MenuType.Input);

  3. menu.AddItem(new GUIContent("Add Output"), false, MenuCallback, MenuType.Output);

  4. menu.AddItem(new GUIContent("Add Cale"), false, MenuCallback, MenuType.Cale);

  5. menu.AddItem(new GUIContent("Add Comp"), false, MenuCallback, MenuType.Comp);

  6.  
  7. menu.ShowAsContext();

  8.  
  9. e.Use();

 

2.窗口里的弹出窗口(本案例核心)

EditorWindow.BeginWindows 开始窗口

WindowRect = GUI.Window(id,窗口Rect, 绘制完回调, 弹出窗口名);

EditorWindow.EndWindows (); 结束窗口

 

3.设置弹出窗口可拖动

GUI.DragWindow(); 

 

4.关于绘制贝塞尔曲线,可以查看另一片关于Handle的·文章:http://blog.csdn.net/qq_33337811/article/details/64571782
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

项目代码:

结点基类:

  1. public class BaseNode

  2. {

  3. public string windowTitle; //结点窗口标题

  4. public Rect WindowRect; //窗口框

  5.  
  6. public virtual void DrawWindow()

  7. {

  8. windowTitle = EditorGUILayout.TextField("Title", windowTitle);

  9. }

  10.  
  11. public virtual void SetInput(InputNode inputNode, Vector2 mousePos)

  12. {

  13.  
  14. }

  15.  
  16. public virtual void DrawBezier()

  17. {

  18. }

  19.  
  20. public virtual void DeleteNode(BaseNode node)

  21. {

  22. }

  23. }

然后所有类型的结点窗口都继承自这个类:

 

1.输入节点:(如下图效果)

  1. using System;

  2. using UnityEngine;

  3. using System.Collections;

  4. using UnityEditor;

  5.  
  6. public enum InputType //输入类型

  7. {

  8. Number, //数字

  9. RandomNumber //随机数

  10. }

  11. public class InputNode : BaseNode

  12. {

  13. // 获取用户选择的输入类型>

  14. private InputType type = InputType.Number;

  15.  
  16. //获取输入的值

  17. private string inputValue = "";

  18.  
  19. // 获取随机值

  20. private string rFrom;

  21. private string rTo;

  22.  
  23. private string resultNumber; //结果数字

  24.  
  25. public InputNode ()

  26. {

  27. windowTitle = "InputNode";

  28. }

  29.  
  30. public override void DrawWindow () //绘制窗口

  31. {

  32. base.DrawWindow();

  33. type = (InputType) EditorGUILayout.EnumPopup("Input Type", type);

  34.  
  35. if (type == InputType.Number)

  36. {

  37. inputValue = EditorGUILayout.TextField("Value", inputValue);

  38. resultNumber = inputValue;

  39. }

  40. else

  41. {

  42. rFrom = EditorGUILayout.TextField("From", rFrom);

  43. rTo = EditorGUILayout.TextField("To", rTo);

  44.  
  45. if (GUILayout.Button("Create Random Number"))

  46. {

  47. CreateRandomNumber();

  48. }

  49. }

  50. }

  51.  
  52. //创建随机数

  53. private void CreateRandomNumber()

  54. {

  55. int from = 0;

  56. int to = 0;

  57. Int32.TryParse(rFrom, out from);

  58. Int32.TryParse(rTo, out to);

  59. Debug.Log(from + "||" + to);

  60.  
  61. resultNumber = UnityEngine.Random.Range(from, to) + "";

  62. Debug.Log(resultNumber);

  63. }

  64.  
  65. //获取得到的数字

  66. public string GetResult()

  67. {

  68. return resultNumber;

  69. }

  70. }

2.输出节点:

 

  1. using UnityEngine;

  2. using System.Collections;

  3. using UnityEditor;

  4.  
  5. public class OutputNode : BaseNode

  6. {

  7. private string input1Value;

  8.  
  9. //持有输入结点的引用

  10. private InputNode inputNode;

  11.  
  12. //OutputNode 的 Input1 输入框的矩形

  13. private Rect input1Rect;

  14.  
  15. public OutputNode ()

  16. {

  17. windowTitle = "OutputNode";

  18. }

  19.  
  20. public override void DrawWindow ()

  21. {

  22. base.DrawWindow();

  23.  
  24. if (inputNode != null)

  25. {

  26. input1Value = inputNode.GetResult();//获取输入的数字

  27. }

  28. input1Value = EditorGUILayout.TextField("Input1:", input1Value);

  29.  
  30. if (Event.current.type == EventType.Repaint)

  31. {

  32. input1Rect = GUILayoutUtility.GetLastRect();

  33. }

  34. }

  35.  
  36. public override void SetInput(InputNode inputNode, Vector2 mousePos)

  37. {

  38. mousePos.x -= WindowRect.x;

  39. mousePos.y -= WindowRect.y;

  40.  
  41. //获取我们的输入结点的引用

  42. //如果我们的鼠标点击在了OutputNode 的 input1 的文本框的 Rect 中时 执行的操作

  43. if (input1Rect.Contains(mousePos))

  44. {

  45. Debug.Log("Enter");

  46. //将输入结点的引用给OutputNode

  47. this.inputNode = inputNode;

  48. }

  49.  
  50. inputNode = null;

  51. }

  52.  
  53. public override void DrawBezier()

  54. {

  55. if (inputNode != null)

  56. {

  57. Rect rect = input1Rect;

  58. rect.x = rect.x + WindowRect.x;

  59. rect.y = rect.y + WindowRect.y;

  60. rect.width = 1;

  61. rect.height = 1;

  62.  
  63. //rect.x += WindowRect.x 简化的写法

  64. NodeEditorWindow.DrawBezier(inputNode.WindowRect, rect);

  65. }

  66. }

  67. public override void DeleteNode(BaseNode node)

  68. {

  69. if (inputNode == node)

  70. {

  71. inputNode = null;

  72. }

  73. }

  74. }


3.计算结点

  1. using UnityEngine;

  2. using System.Collections;

  3. using UnityEditor;

  4.  
  5. public enum CalcType //计算方式

  6. {

  7. Greater,

  8. Less,

  9. Equal

  10. }

  11. public class CaleNode : BaseNode

  12. {

  13. private CalcType caleType = CalcType.Greater;

  14.  
  15. private string input1Value;

  16. private string input2Value;

  17.  
  18. public CaleNode ()

  19. {

  20. windowTitle = "CaleNode";

  21. }

  22.  
  23. public override void DrawWindow ()

  24. {

  25. base.DrawWindow();

  26. caleType = (CalcType)EditorGUILayout.EnumPopup("Calculation Type", caleType);

  27. input1Value = EditorGUILayout.TextField("input1", input1Value);

  28. input2Value = EditorGUILayout.TextField("input2", input2Value);

  29. }

  30. }


4.比较结点

  1. using UnityEngine;

  2. using System.Collections;

  3. using UnityEditor;

  4.  
  5. public enum CompType //比较方式

  6. {

  7. Greater,

  8. Less,

  9. Equal

  10. }

  11.  
  12. public class CompNode : BaseNode

  13. {

  14. private CompType compType = CompType.Greater;

  15.  
  16. private string input1Value;

  17. private string input2Value;

  18.  
  19. private InputNode inputNode1;

  20.  
  21. private InputNode inputNode2;

  22.  
  23. /// <summary>

  24. /// OutputNode 的 Input1 输入框的矩形

  25. /// </summary>

  26. private Rect input1Rect;

  27.  
  28. /// <summary>

  29. /// OutputNode 的 Input2 输入框的矩形

  30. /// </summary>

  31. private Rect input2Rect;

  32.  
  33. public CompNode ()

  34. {

  35. windowTitle = "CompNode";

  36. }

  37.  
  38. public override void DrawWindow()

  39. {

  40. base.DrawWindow();

  41. compType = (CompType) EditorGUILayout.EnumPopup("Calculation Type", compType);

  42.  
  43. if (inputNode1 != null)

  44. {

  45. input1Value = inputNode1.GetResult();

  46. }

  47.  
  48. input1Value = EditorGUILayout.TextField("input1", input1Value);

  49. if (Event.current.type == EventType.Repaint)

  50. {

  51. input1Rect = GUILayoutUtility.GetLastRect();

  52. }

  53. if (inputNode2 != null)

  54. {

  55. input2Value = inputNode2.GetResult();

  56. }

  57. input2Value = EditorGUILayout.TextField("input2", input2Value);

  58. if (Event.current.type == EventType.Repaint)

  59. {

  60. input2Rect = GUILayoutUtility.GetLastRect();

  61. }

  62. }

  63.  
  64. public override void SetInput (InputNode inputNode, Vector2 mousePos)

  65. {

  66. mousePos.x -= WindowRect.x;

  67. mousePos.y -= WindowRect.y;

  68.  
  69. //获取我们的输入结点的引用

  70. //如果我们的鼠标点击在了OutputNode 的 input1 的文本框的 Rect 中时 执行的操作

  71. if (input1Rect.Contains(mousePos))

  72. {

  73. Debug.Log("Enter");

  74. //将输入结点的引用给OutputNode

  75. this.inputNode1 = inputNode;

  76. }

  77.  
  78. if (input2Rect.Contains(mousePos))

  79. {

  80. Debug.Log("Enter");

  81. //将输入结点的引用给OutputNode

  82. this.inputNode2 = inputNode;

  83. }

  84. }

  85.  
  86. public override void DrawBezier ()

  87. {

  88. if (inputNode1 != null)

  89. {

  90. Rect rect = input1Rect;

  91. rect.x = rect.x + WindowRect.x;

  92. rect.y = rect.y + WindowRect.y;

  93. rect.width = 1;

  94. rect.height = 1;

  95.  
  96. //rect.x += WindowRect.x 简化的写法

  97. NodeEditorWindow.DrawBezier(inputNode1.WindowRect, rect);

  98. }

  99.  
  100. if (inputNode2 != null)

  101. {

  102. Rect rect = input2Rect;

  103. rect.x = rect.x + WindowRect.x;

  104. rect.y = rect.y + WindowRect.y;

  105. rect.width = 1;

  106. rect.height = 1;

  107.  
  108. //rect.x += WindowRect.x 简化的写法

  109. NodeEditorWindow.DrawBezier(inputNode2.WindowRect, rect);

  110. }

  111. }

  112. public override void DeleteNode (BaseNode node)

  113. {

  114. if (inputNode1 == node)

  115. {

  116. inputNode1 = null;

  117. }

  118.  
  119. if (inputNode2 == node)

  120. {

  121. inputNode2 = null;

  122. }

  123. }

  124. }


结点类准备好了,现在来绘制窗口:

继承自EditorWindow的类编辑窗口:

  1. using UnityEngine;

  2. using System.Collections;

  3. using UnityEditor;

  4. using System;

  5. using System.Collections.Generic;

  6.  
  7. public enum MenuType //菜单类型

  8. {

  9. Input,

  10. Output,

  11. Cale,

  12. Comp,

  13. Delete,

  14. Line

  15. }

  16. public class NodeEditorWindow : EditorWindow

  17. {

  18. /// <summary>

  19. /// 窗口容器,用于存放窗口

  20. /// </summary>

  21. private List<BaseNode> windows = new List<BaseNode>();

  22.  
  23. /// <summary>

  24. /// 判断是否点击在窗口上

  25. /// </summary>

  26. private bool isClickedOnWindow = false;

  27.  
  28. /// <summary>

  29. /// 当前选中的窗口的下标

  30. /// </summary>

  31. private int selectedIndex = -1;

  32.  
  33. /// <summary>

  34. /// 当前鼠标的位置

  35. /// </summary>

  36. private Vector2 mousePos;

  37.  
  38. /// <summary>

  39. /// 判断当前是否为画线模式

  40. /// </summary>

  41. private bool isDrawLineModel = false;

  42.  
  43. /// <summary>

  44. /// 当前选中的Node

  45. /// </summary>

  46. private BaseNode selectNode;

  47.  
  48. private BaseNode drawModeSelectedNode;

  49.  
  50. [MenuItem("Tool/My Node Editor")]

  51. static void OpenWindow() //打开窗口

  52. {

  53. GetWindow<NodeEditorWindow>();

  54. }

  55.  
  56. //开始绘制

  57. void OnGUI()

  58. {

  59. //1.获取当前事件

  60. Event e = Event.current;

  61. //获取鼠标的位置

  62. mousePos = e.mousePosition;

  63.  
  64. //2.创建我们的菜单

  65. //当我们按下鼠标右键时,执行的操作

  66. if (e.button == 1 && e.isMouse && !isDrawLineModel )

  67. {

  68. CreateMenu(e); //创建菜单

  69. }

  70. //在画线状态下点击鼠标左键时执行的操作

  71. else if (e.button == 0 && e.isMouse && isDrawLineModel)

  72. {

  73. //找到画线模式下选中的结点

  74. FoundSelectedWindow();

  75. drawModeSelectedNode = windows[selectedIndex];

  76.  
  77.  
  78. if (isClickedOnWindow && drawModeSelectedNode != null)

  79. {

  80. //1.否则,将输入结点的引用给输出结点

  81. drawModeSelectedNode.SetInput((InputNode)selectNode,mousePos);

  82. //isDrawLineModel = false;

  83. //selectNode = null;

  84. //2.将线给连上

  85. }

  86. //else

  87. //{

  88. // isDrawLineModel = false;

  89. // selectNode = null;

  90. //}

  91.  
  92. //1.当我们点击的位置不在窗口上时,我们停止画线

  93. //2.当我们点击在窗口上时,判断是否点击的时同一个窗口

  94. //如果点击的是同一个窗口的话,那么我们也停止画线

  95. //if (!isClickedOnWindow || drawModeSelectedNode == selectNode)

  96. //{

  97. // isDrawLineModel = false;

  98. // selectNode = null;

  99. //}

  100. isDrawLineModel = false;

  101. selectNode = null;

  102. }

  103.  
  104.  
  105. //画线功能

  106. if (isDrawLineModel && selectNode != null)

  107. {

  108. //2.找到结束的位置(矩形)

  109. Rect endRect = new Rect(mousePos, new Vector2(10, 10));

  110. DrawBezier(selectNode.WindowRect, endRect);

  111.  
  112. Repaint();

  113. }

  114.  
  115. //维护画线功能

  116. for (int i = 0; i < windows.Count; i++)

  117. {

  118. windows[i].DrawBezier();

  119. }

  120.  
  121. BeginWindows(); //开始绘制弹出窗口

  122.  
  123. for (int i = 0; i < windows.Count; i++)

  124. {

  125. windows[i].WindowRect = GUI.Window(i, windows[i].WindowRect, WindowCallback, windows[i].windowTitle);

  126. }

  127.  
  128. EndWindows();//结束绘制弹出窗口

  129. }

  130.  
  131. private void CreateMenu (Event e)

  132. {

  133. FoundSelectedWindow(); //尝试寻找点击的窗体

  134.  
  135. //当我们点击在窗口的时候,我们可以删除窗口和画线

  136. if (isClickedOnWindow)

  137. {

  138. GenericMenu menu = new GenericMenu();

  139. menu.AddItem(new GUIContent("Delete Node"), false, MenuCallback, MenuType.Delete);

  140. menu.AddItem(new GUIContent("Draw Line"), false, MenuCallback, MenuType.Line);

  141.  
  142. menu.ShowAsContext();

  143.  
  144. e.Use();

  145.  
  146. isClickedOnWindow = false;

  147. }

  148. //当我们点击在窗口外时,可以创建结点

  149. else

  150. {

  151. GenericMenu menu = new GenericMenu();

  152. menu.AddItem(new GUIContent("Add Input"), false, MenuCallback, MenuType.Input);

  153. menu.AddItem(new GUIContent("Add Output"), false, MenuCallback, MenuType.Output);

  154. menu.AddItem(new GUIContent("Add Cale"), true, MenuCallback, MenuType.Cale);

  155. menu.AddItem(new GUIContent("Add Comp"), false, MenuCallback, MenuType.Comp);

  156.  
  157. menu.ShowAsContext();

  158.  
  159. e.Use();

  160. }

  161.  
  162. }

  163.  
  164. //设置选择的窗体

  165. private void FoundSelectedWindow ()

  166. {

  167. for (int i = 0; i < windows.Count; i++)

  168. {

  169. if (windows[i].WindowRect.Contains(mousePos))

  170. {

  171. Debug.Log(i);

  172. isClickedOnWindow = true;

  173. selectedIndex = i;

  174. break;

  175. }

  176. else

  177. {

  178. isClickedOnWindow = false;

  179. }

  180. }

  181. }

  182.  
  183. //弹出窗口绘制完后绘制窗口里内容

  184. private void WindowCallback(int id)

  185. {

  186. windows[id].DrawWindow();

  187. GUI.DragWindow(); //设置窗口可拖动

  188. }

  189.  
  190. private void MenuCallback (object type)

  191. {

  192. Debug.Log("Enter!!!" + ((MenuType)type).ToString());

  193. switch ((MenuType)type)

  194. {

  195. //在鼠标位置创建指定大小的小窗口

  196. case MenuType.Input:

  197. InputNode input = new InputNode();

  198. input.WindowRect = new Rect(mousePos.x,mousePos.y,200,150);

  199. windows.Add(input);

  200. break;

  201. case MenuType.Output:

  202. OutputNode output = new OutputNode();

  203. output.WindowRect = new Rect(mousePos.x, mousePos.y, 200, 150);

  204. windows.Add(output);

  205. break;

  206. case MenuType.Cale:

  207. CaleNode cale = new CaleNode();

  208. cale.WindowRect = new Rect(mousePos.x, mousePos.y, 200, 150);

  209. windows.Add(cale);

  210. break;

  211. case MenuType.Comp:

  212. CompNode comp = new CompNode();

  213. comp.WindowRect = new Rect(mousePos.x, mousePos.y, 200, 150);

  214. windows.Add(comp);

  215. break;

  216. case MenuType.Delete:

  217. //删除对应的子窗口

  218. for (int i = 0; i < windows.Count; i++)

  219. {

  220. windows[i].DeleteNode(windows[selectedIndex]);

  221. }

  222.  
  223. windows.RemoveAt(selectedIndex);

  224. break;

  225. case MenuType.Line:

  226. //写我们的画线逻辑

  227. FoundSelectedWindow();

  228. //1.找到开始的位置(矩形)

  229. selectNode = windows[selectedIndex];

  230. //2.切换当前模式为画线模式

  231. isDrawLineModel = true;

  232. break;

  233. default:

  234. throw new ArgumentOutOfRangeException("type", type, null);

  235. }

  236. }

  237.  
  238. public static void DrawBezier(Rect start, Rect end)

  239. {

  240. Vector3 startPos = new Vector3(start.x + start.width/2, start.y + start.height/2, 0);

  241. Vector3 endPos = new Vector3(end.x + end.width / 2, end.y + end.height / 2, 0);

  242. Vector3 startTan = startPos + Vector3.right*50;

  243. Vector3 endTan = endPos + Vector3.left * 50;

  244. Color shadow = new Color(0,0,0,0.7f);

  245.  
  246. for (int i = 0; i < 5; i++)

  247. {

  248. Handles.DrawBezier(startPos, endPos, startTan, endTan, shadow, null, 1+(i*2));

  249. }

  250.  
  251. Handles.DrawBezier(startPos,endPos,startTan,endTan,Color.black, null,1);

  252. }

  253. }


效果:

 

结束语:

本文转自:http://mp.weixin.qq.com/s/CV_UTPMsWmz5w0gSOIPyFQ,本人学习了一下稍微改动了一下,感谢楼主的无私奉献,请点击连接查看原文,尊重楼主版权。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jack Yan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值