转自: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:在给定屏幕矩形位置显示菜单。
-
GenericMenu menu = new GenericMenu(); -
menu.AddItem(new GUIContent("Add Input"), false, MenuCallback, MenuType.Input); -
menu.AddItem(new GUIContent("Add Output"), false, MenuCallback, MenuType.Output); -
menu.AddItem(new GUIContent("Add Cale"), false, MenuCallback, MenuType.Cale); -
menu.AddItem(new GUIContent("Add Comp"), false, MenuCallback, MenuType.Comp); -
menu.ShowAsContext(); -
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
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
项目代码:
结点基类:
-
public class BaseNode -
{ -
public string windowTitle; //结点窗口标题 -
public Rect WindowRect; //窗口框 -
public virtual void DrawWindow() -
{ -
windowTitle = EditorGUILayout.TextField("Title", windowTitle); -
} -
public virtual void SetInput(InputNode inputNode, Vector2 mousePos) -
{ -
} -
public virtual void DrawBezier() -
{ -
} -
public virtual void DeleteNode(BaseNode node) -
{ -
} -
}
然后所有类型的结点窗口都继承自这个类:
1.输入节点:(如下图效果)
-
using System; -
using UnityEngine; -
using System.Collections; -
using UnityEditor; -
public enum InputType //输入类型 -
{ -
Number, //数字 -
RandomNumber //随机数 -
} -
public class InputNode : BaseNode -
{ -
// 获取用户选择的输入类型> -
private InputType type = InputType.Number; -
//获取输入的值 -
private string inputValue = ""; -
// 获取随机值 -
private string rFrom; -
private string rTo; -
private string resultNumber; //结果数字 -
public InputNode () -
{ -
windowTitle = "InputNode"; -
} -
public override void DrawWindow () //绘制窗口 -
{ -
base.DrawWindow(); -
type = (InputType) EditorGUILayout.EnumPopup("Input Type", type); -
if (type == InputType.Number) -
{ -
inputValue = EditorGUILayout.TextField("Value", inputValue); -
resultNumber = inputValue; -
} -
else -
{ -
rFrom = EditorGUILayout.TextField("From", rFrom); -
rTo = EditorGUILayout.TextField("To", rTo); -
if (GUILayout.Button("Create Random Number")) -
{ -
CreateRandomNumber(); -
} -
} -
} -
//创建随机数 -
private void CreateRandomNumber() -
{ -
int from = 0; -
int to = 0; -
Int32.TryParse(rFrom, out from); -
Int32.TryParse(rTo, out to); -
Debug.Log(from + "||" + to); -
resultNumber = UnityEngine.Random.Range(from, to) + ""; -
Debug.Log(resultNumber); -
} -
//获取得到的数字 -
public string GetResult() -
{ -
return resultNumber; -
} -
}
2.输出节点:
-
using UnityEngine; -
using System.Collections; -
using UnityEditor; -
public class OutputNode : BaseNode -
{ -
private string input1Value; -
//持有输入结点的引用 -
private InputNode inputNode; -
//OutputNode 的 Input1 输入框的矩形 -
private Rect input1Rect; -
public OutputNode () -
{ -
windowTitle = "OutputNode"; -
} -
public override void DrawWindow () -
{ -
base.DrawWindow(); -
if (inputNode != null) -
{ -
input1Value = inputNode.GetResult();//获取输入的数字 -
} -
input1Value = EditorGUILayout.TextField("Input1:", input1Value); -
if (Event.current.type == EventType.Repaint) -
{ -
input1Rect = GUILayoutUtility.GetLastRect(); -
} -
} -
public override void SetInput(InputNode inputNode, Vector2 mousePos) -
{ -
mousePos.x -= WindowRect.x; -
mousePos.y -= WindowRect.y; -
//获取我们的输入结点的引用 -
//如果我们的鼠标点击在了OutputNode 的 input1 的文本框的 Rect 中时 执行的操作 -
if (input1Rect.Contains(mousePos)) -
{ -
Debug.Log("Enter"); -
//将输入结点的引用给OutputNode -
this.inputNode = inputNode; -
} -
inputNode = null; -
} -
public override void DrawBezier() -
{ -
if (inputNode != null) -
{ -
Rect rect = input1Rect; -
rect.x = rect.x + WindowRect.x; -
rect.y = rect.y + WindowRect.y; -
rect.width = 1; -
rect.height = 1; -
//rect.x += WindowRect.x 简化的写法 -
NodeEditorWindow.DrawBezier(inputNode.WindowRect, rect); -
} -
} -
public override void DeleteNode(BaseNode node) -
{ -
if (inputNode == node) -
{ -
inputNode = null; -
} -
} -
}
3.计算结点
-
using UnityEngine; -
using System.Collections; -
using UnityEditor; -
public enum CalcType //计算方式 -
{ -
Greater, -
Less, -
Equal -
} -
public class CaleNode : BaseNode -
{ -
private CalcType caleType = CalcType.Greater; -
private string input1Value; -
private string input2Value; -
public CaleNode () -
{ -
windowTitle = "CaleNode"; -
} -
public override void DrawWindow () -
{ -
base.DrawWindow(); -
caleType = (CalcType)EditorGUILayout.EnumPopup("Calculation Type", caleType); -
input1Value = EditorGUILayout.TextField("input1", input1Value); -
input2Value = EditorGUILayout.TextField("input2", input2Value); -
} -
}
4.比较结点
-
using UnityEngine; -
using System.Collections; -
using UnityEditor; -
public enum CompType //比较方式 -
{ -
Greater, -
Less, -
Equal -
} -
public class CompNode : BaseNode -
{ -
private CompType compType = CompType.Greater; -
private string input1Value; -
private string input2Value; -
private InputNode inputNode1; -
private InputNode inputNode2; -
/// <summary> -
/// OutputNode 的 Input1 输入框的矩形 -
/// </summary> -
private Rect input1Rect; -
/// <summary> -
/// OutputNode 的 Input2 输入框的矩形 -
/// </summary> -
private Rect input2Rect; -
public CompNode () -
{ -
windowTitle = "CompNode"; -
} -
public override void DrawWindow() -
{ -
base.DrawWindow(); -
compType = (CompType) EditorGUILayout.EnumPopup("Calculation Type", compType); -
if (inputNode1 != null) -
{ -
input1Value = inputNode1.GetResult(); -
} -
input1Value = EditorGUILayout.TextField("input1", input1Value); -
if (Event.current.type == EventType.Repaint) -
{ -
input1Rect = GUILayoutUtility.GetLastRect(); -
} -
if (inputNode2 != null) -
{ -
input2Value = inputNode2.GetResult(); -
} -
input2Value = EditorGUILayout.TextField("input2", input2Value); -
if (Event.current.type == EventType.Repaint) -
{ -
input2Rect = GUILayoutUtility.GetLastRect(); -
} -
} -
public override void SetInput (InputNode inputNode, Vector2 mousePos) -
{ -
mousePos.x -= WindowRect.x; -
mousePos.y -= WindowRect.y; -
//获取我们的输入结点的引用 -
//如果我们的鼠标点击在了OutputNode 的 input1 的文本框的 Rect 中时 执行的操作 -
if (input1Rect.Contains(mousePos)) -
{ -
Debug.Log("Enter"); -
//将输入结点的引用给OutputNode -
this.inputNode1 = inputNode; -
} -
if (input2Rect.Contains(mousePos)) -
{ -
Debug.Log("Enter"); -
//将输入结点的引用给OutputNode -
this.inputNode2 = inputNode; -
} -
} -
public override void DrawBezier () -
{ -
if (inputNode1 != null) -
{ -
Rect rect = input1Rect; -
rect.x = rect.x + WindowRect.x; -
rect.y = rect.y + WindowRect.y; -
rect.width = 1; -
rect.height = 1; -
//rect.x += WindowRect.x 简化的写法 -
NodeEditorWindow.DrawBezier(inputNode1.WindowRect, rect); -
} -
if (inputNode2 != null) -
{ -
Rect rect = input2Rect; -
rect.x = rect.x + WindowRect.x; -
rect.y = rect.y + WindowRect.y; -
rect.width = 1; -
rect.height = 1; -
//rect.x += WindowRect.x 简化的写法 -
NodeEditorWindow.DrawBezier(inputNode2.WindowRect, rect); -
} -
} -
public override void DeleteNode (BaseNode node) -
{ -
if (inputNode1 == node) -
{ -
inputNode1 = null; -
} -
if (inputNode2 == node) -
{ -
inputNode2 = null; -
} -
} -
}
结点类准备好了,现在来绘制窗口:
继承自EditorWindow的类编辑窗口:
-
using UnityEngine; -
using System.Collections; -
using UnityEditor; -
using System; -
using System.Collections.Generic; -
public enum MenuType //菜单类型 -
{ -
Input, -
Output, -
Cale, -
Comp, -
Delete, -
Line -
} -
public class NodeEditorWindow : EditorWindow -
{ -
/// <summary> -
/// 窗口容器,用于存放窗口 -
/// </summary> -
private List<BaseNode> windows = new List<BaseNode>(); -
/// <summary> -
/// 判断是否点击在窗口上 -
/// </summary> -
private bool isClickedOnWindow = false; -
/// <summary> -
/// 当前选中的窗口的下标 -
/// </summary> -
private int selectedIndex = -1; -
/// <summary> -
/// 当前鼠标的位置 -
/// </summary> -
private Vector2 mousePos; -
/// <summary> -
/// 判断当前是否为画线模式 -
/// </summary> -
private bool isDrawLineModel = false; -
/// <summary> -
/// 当前选中的Node -
/// </summary> -
private BaseNode selectNode; -
private BaseNode drawModeSelectedNode; -
[MenuItem("Tool/My Node Editor")] -
static void OpenWindow() //打开窗口 -
{ -
GetWindow<NodeEditorWindow>(); -
} -
//开始绘制 -
void OnGUI() -
{ -
//1.获取当前事件 -
Event e = Event.current; -
//获取鼠标的位置 -
mousePos = e.mousePosition; -
//2.创建我们的菜单 -
//当我们按下鼠标右键时,执行的操作 -
if (e.button == 1 && e.isMouse && !isDrawLineModel ) -
{ -
CreateMenu(e); //创建菜单 -
} -
//在画线状态下点击鼠标左键时执行的操作 -
else if (e.button == 0 && e.isMouse && isDrawLineModel) -
{ -
//找到画线模式下选中的结点 -
FoundSelectedWindow(); -
drawModeSelectedNode = windows[selectedIndex]; -
if (isClickedOnWindow && drawModeSelectedNode != null) -
{ -
//1.否则,将输入结点的引用给输出结点 -
drawModeSelectedNode.SetInput((InputNode)selectNode,mousePos); -
//isDrawLineModel = false; -
//selectNode = null; -
//2.将线给连上 -
} -
//else -
//{ -
// isDrawLineModel = false; -
// selectNode = null; -
//} -
//1.当我们点击的位置不在窗口上时,我们停止画线 -
//2.当我们点击在窗口上时,判断是否点击的时同一个窗口 -
//如果点击的是同一个窗口的话,那么我们也停止画线 -
//if (!isClickedOnWindow || drawModeSelectedNode == selectNode) -
//{ -
// isDrawLineModel = false; -
// selectNode = null; -
//} -
isDrawLineModel = false; -
selectNode = null; -
} -
//画线功能 -
if (isDrawLineModel && selectNode != null) -
{ -
//2.找到结束的位置(矩形) -
Rect endRect = new Rect(mousePos, new Vector2(10, 10)); -
DrawBezier(selectNode.WindowRect, endRect); -
Repaint(); -
} -
//维护画线功能 -
for (int i = 0; i < windows.Count; i++) -
{ -
windows[i].DrawBezier(); -
} -
BeginWindows(); //开始绘制弹出窗口 -
for (int i = 0; i < windows.Count; i++) -
{ -
windows[i].WindowRect = GUI.Window(i, windows[i].WindowRect, WindowCallback, windows[i].windowTitle); -
} -
EndWindows();//结束绘制弹出窗口 -
} -
private void CreateMenu (Event e) -
{ -
FoundSelectedWindow(); //尝试寻找点击的窗体 -
//当我们点击在窗口的时候,我们可以删除窗口和画线 -
if (isClickedOnWindow) -
{ -
GenericMenu menu = new GenericMenu(); -
menu.AddItem(new GUIContent("Delete Node"), false, MenuCallback, MenuType.Delete); -
menu.AddItem(new GUIContent("Draw Line"), false, MenuCallback, MenuType.Line); -
menu.ShowAsContext(); -
e.Use(); -
isClickedOnWindow = false; -
} -
//当我们点击在窗口外时,可以创建结点 -
else -
{ -
GenericMenu menu = new GenericMenu(); -
menu.AddItem(new GUIContent("Add Input"), false, MenuCallback, MenuType.Input); -
menu.AddItem(new GUIContent("Add Output"), false, MenuCallback, MenuType.Output); -
menu.AddItem(new GUIContent("Add Cale"), true, MenuCallback, MenuType.Cale); -
menu.AddItem(new GUIContent("Add Comp"), false, MenuCallback, MenuType.Comp); -
menu.ShowAsContext(); -
e.Use(); -
} -
} -
//设置选择的窗体 -
private void FoundSelectedWindow () -
{ -
for (int i = 0; i < windows.Count; i++) -
{ -
if (windows[i].WindowRect.Contains(mousePos)) -
{ -
Debug.Log(i); -
isClickedOnWindow = true; -
selectedIndex = i; -
break; -
} -
else -
{ -
isClickedOnWindow = false; -
} -
} -
} -
//弹出窗口绘制完后绘制窗口里内容 -
private void WindowCallback(int id) -
{ -
windows[id].DrawWindow(); -
GUI.DragWindow(); //设置窗口可拖动 -
} -
private void MenuCallback (object type) -
{ -
Debug.Log("Enter!!!" + ((MenuType)type).ToString()); -
switch ((MenuType)type) -
{ -
//在鼠标位置创建指定大小的小窗口 -
case MenuType.Input: -
InputNode input = new InputNode(); -
input.WindowRect = new Rect(mousePos.x,mousePos.y,200,150); -
windows.Add(input); -
break; -
case MenuType.Output: -
OutputNode output = new OutputNode(); -
output.WindowRect = new Rect(mousePos.x, mousePos.y, 200, 150); -
windows.Add(output); -
break; -
case MenuType.Cale: -
CaleNode cale = new CaleNode(); -
cale.WindowRect = new Rect(mousePos.x, mousePos.y, 200, 150); -
windows.Add(cale); -
break; -
case MenuType.Comp: -
CompNode comp = new CompNode(); -
comp.WindowRect = new Rect(mousePos.x, mousePos.y, 200, 150); -
windows.Add(comp); -
break; -
case MenuType.Delete: -
//删除对应的子窗口 -
for (int i = 0; i < windows.Count; i++) -
{ -
windows[i].DeleteNode(windows[selectedIndex]); -
} -
windows.RemoveAt(selectedIndex); -
break; -
case MenuType.Line: -
//写我们的画线逻辑 -
FoundSelectedWindow(); -
//1.找到开始的位置(矩形) -
selectNode = windows[selectedIndex]; -
//2.切换当前模式为画线模式 -
isDrawLineModel = true; -
break; -
default: -
throw new ArgumentOutOfRangeException("type", type, null); -
} -
} -
public static void DrawBezier(Rect start, Rect end) -
{ -
Vector3 startPos = new Vector3(start.x + start.width/2, start.y + start.height/2, 0); -
Vector3 endPos = new Vector3(end.x + end.width / 2, end.y + end.height / 2, 0); -
Vector3 startTan = startPos + Vector3.right*50; -
Vector3 endTan = endPos + Vector3.left * 50; -
Color shadow = new Color(0,0,0,0.7f); -
for (int i = 0; i < 5; i++) -
{ -
Handles.DrawBezier(startPos, endPos, startTan, endTan, shadow, null, 1+(i*2)); -
} -
Handles.DrawBezier(startPos,endPos,startTan,endTan,Color.black, null,1); -
} -
}
效果:
结束语:
本文转自:http://mp.weixin.qq.com/s/CV_UTPMsWmz5w0gSOIPyFQ,本人学习了一下稍微改动了一下,感谢楼主的无私奉献,请点击连接查看原文,尊重楼主版权。