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:在给定屏幕矩形位置显示菜单。
-
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,本人学习了一下稍微改动了一下,感谢楼主的无私奉献,请点击连接查看原文,尊重楼主版权。