在Unity中创建基于Node节点的编辑器 (一)
孙广东 2018.5.13
Unity AssetStore中关于Node节点 编辑器相关的插件可是数不胜数, 状态机,行为树,Shader 可视化等等。
Unity自己也有 Animator的窗口使用, 还有新的Shader Graph。
现在Unity的编辑器代码已经开源了,还没有时间看。
using UnityEngine ;
using UnityEditor ;
using System . Collections . Generic ;
public class NodeBasedEditor : EditorWindow
{
[ MenuItem ( "Window/Node Based Editor" )]
private static void OpenWindow ()
{
NodeBasedEditor window = GetWindow < NodeBasedEditor > ();
window . titleContent = new GUIContent ( "Node Based Editor" );
}
private void OnGUI ()
{
DrawNodes ();
ProcessEvents ( Event . current );
if ( GUI . changed ) Repaint ();
}
private void DrawNodes ()
{
}
private void ProcessEvents ( Event e )
{
}
}
|
using System ;
using UnityEditor ;
using UnityEngine ;
public class Node
{
public Rect rect ;
public string title ;
public GUIStyle style ;
public Node ( Vector2 position , float width , float height , GUIStyle nodeStyle )
{
rect = new Rect ( position . x , position . y , width , height );
style = nodeStyle ;
}
public void Drag ( Vector2 delta )
{
rect . position += delta ;
}
public void Draw ()
{
GUI . Box ( rect , title , style );
}
public bool ProcessEvents ( Event e )
{
return false ;
}
}
|
using UnityEngine ;
using UnityEditor ;
using System . Collections . Generic ;
public class NodeBasedEditor : EditorWindow
{
private List < Node > nodes ;
[ MenuItem ( "Window/Node Based Editor" )]
private static void OpenWindow ()
{
NodeBasedEditor window = GetWindow < NodeBasedEditor > ();
window . titleContent = new GUIContent ( "Node Based Editor" );
}
private void OnGUI ()
{
DrawNodes ();
ProcessEvents ( Event . current );
if ( GUI . changed ) Repaint ();
}
private void DrawNodes ()
{
if ( nodes != null )
{
for ( int i = 0 ; i < nodes . Count ; i ++ )
{
nodes [ i ]. Draw ();
}
}
}
private void ProcessEvents ( Event e )
{
}
}
|
using UnityEngine ;
using UnityEditor ;
using System . Collections . Generic ;
public class NodeBasedEditor : EditorWindow
{
private List < Node > nodes ;
private GUIStyle nodeStyle ;
[ MenuItem ( "Window/Node Based Editor" )]
private static void OpenWindow ()
{
NodeBasedEditor window = GetWindow < NodeBasedEditor > ();
window . titleContent = new GUIContent ( "Node Based Editor" );
}
private void OnEnable ()
{
nodeStyle = new GUIStyle ();
nodeStyle . normal . background = EditorGUIUtility . Load ( "builtin skins/darkskin/images/node1.png" ) as Texture2D ;
nodeStyle . border = new RectOffset ( 12 , 12 , 12 , 12 );
}
private void OnGUI ()
{
DrawNodes ();
ProcessEvents ( Event . current );
if ( GUI . changed ) Repaint ();
}
private void DrawNodes ()
{
if ( nodes != null )
{
for ( int i = 0 ; i < nodes . Count ; i ++ )
{
nodes [ i ]. Draw ();
}
}
}
private void ProcessEvents ( Event e )
{
switch ( e . type )
{
case EventType . MouseDown :
if ( e . button == 1 )
{
ProcessContextMenu ( e . mousePosition );
}
break ;
}
}
private void ProcessContextMenu ( Vector2 mousePosition )
{
GenericMenu genericMenu = new GenericMenu ();
genericMenu . AddItem ( new GUIContent ( "Add node" ), false , () => OnClickAddNode ( mousePosition ));
genericMenu . ShowAsContext ();
}
private void OnClickAddNode ( Vector2 mousePosition )
{
if ( nodes == null )
{
nodes = new List < Node > ();
}
nodes . Add ( new Node ( mousePosition , 200 , 50 , nodeStyle ));
}
}
|
using System ;
using UnityEditor ;
using UnityEngine ;
public class Node
{
public Rect rect ;
public string title ;
public bool isDragged ;
public GUIStyle style ;
public Node ( Vector2 position , float width , float height , GUIStyle nodeStyle )
{
rect = new Rect ( position . x , position . y , width , height );
style = nodeStyle ;
}
public void Drag ( Vector2 delta )
{
rect . position += delta ;
}
public void Draw ()
{
GUI . Box ( rect , title , style );
}
public bool ProcessEvents ( Event e )
{
switch ( e . type )
{
case EventType . MouseDown :
if ( e . button == 0 )
{
if ( rect . Contains ( e . mousePosition ))
{
isDragged = true ;
GUI . changed = true ;
}
else
{
GUI . changed = true ;
}
}
break ;
case EventType . MouseUp :
isDragged = false ;
break ;
case EventType . MouseDrag :
if ( e . button == 0 && isDragged )
{
Drag ( e . delta );
e . Use ();
return true ;
}
break ;
}
return false ;
}
}
|
private void OnGUI ()
{
DrawNodes ();
ProcessNodeEvents ( Event . current );
ProcessEvents ( Event . current );
if ( GUI . changed ) Repaint ();
}
private void DrawNodes ()
{
if ( nodes != null )
{
for ( int i = 0 ; i < nodes . Count ; i ++ )
{
nodes [ i ]. Draw ();
}
}
}
private void ProcessEvents ( Event e )
{
switch ( e . type )
{
case EventType . MouseDown :
if ( e . button == 1 )
{
ProcessContextMenu ( e . mousePosition );
}
break ;
}
}
private void ProcessNodeEvents ( Event e )
{
if ( nodes != null )
{
for ( int i = nodes . Count - 1 ; i >= 0 ; i -- )
{
bool guiChanged = nodes [ i ]. ProcessEvents ( e );
if ( guiChanged )
{
GUI . changed = true ;
}
}
}
}
private void ProcessContextMenu ( Vector2 mousePosition )
{
GenericMenu genericMenu = new GenericMenu ();
genericMenu . AddItem ( new GUIContent ( "Add node" ), false , () => OnClickAddNode ( mousePosition ));
genericMenu . ShowAsContext ();
}
|
using System ;
using UnityEngine ;
public enum ConnectionPointType { In , Out }
public class ConnectionPoint
{
public Rect rect ;
public ConnectionPointType type ;
public Node node ;
public GUIStyle style ;
public Action < ConnectionPoint > OnClickConnectionPoint ;
public ConnectionPoint ( Node node , ConnectionPointType type , GUIStyle style , Action < ConnectionPoint > OnClickConnectionPoint )
{
this . node = node ;
this . type = type ;
this . style = style ;
this . OnClickConnectionPoint = OnClickConnectionPoint ;
rect = new Rect ( 0 , 0 , 10f , 20f );
}
public void Draw ()
{
rect . y = node . rect . y + ( node . rect . height * 0.5f ) - rect . height * 0.5f ;
switch ( type )
{
case ConnectionPointType . In :
rect . x = node . rect . x - rect . width + 8f ;
break ;
case ConnectionPointType . Out :
rect . x = node . rect . x + node . rect . width - 8f ;
break ;
}
if ( GUI . Button ( rect , "" , style ))
{
if ( OnClickConnectionPoint != null )
{
OnClickConnectionPoint ( this );
}
}
}
}
|
using System ;
using UnityEditor ;
using UnityEngine ;
public class Connection
{
public ConnectionPoint inPoint ;
public ConnectionPoint outPoint ;
public Action < Connection > OnClickRemoveConnection ;
public Connection ( ConnectionPoint inPoint , ConnectionPoint outPoint , Action < Connection > OnClickRemoveConnection )
{
this . inPoint = inPoint ;
this . outPoint = outPoint ;
this . OnClickRemoveConnection = OnClickRemoveConnection ;
}
public void Draw ()
{
Handles . DrawBezier (
inPoint . rect . center ,
outPoint . rect . center ,
inPoint . rect . center + Vector2 . left * 50f ,
outPoint . rect . center - Vector2 . left * 50f ,
Color . white ,
null ,
2f
);
if ( Handles . Button (( inPoint . rect . center + outPoint . rect . center ) * 0.5f , Quaternion . identity , 4 , 8 , Handles . RectangleCap ))
{
if ( OnClickRemoveConnection != null )
{
OnClickRemoveConnection ( this );
}
}
}
}
|
- OnClickInPoint(ConnectionPoint) 处理点击入点。
- OnClickOutPoint(ConnectionPoint) 处理点击出点。
- OnClickRemoveConnection(Connection) 处理单击连接上的删除按钮。
- CreateConnection() 在选择入点和出点时创建连接。
- ClearConnectionSelection() 清除选定的点。
using System ;
using UnityEditor ;
using UnityEngine ;
public class Node
{
public Rect rect ;
public string title ;
public bool isDragged ;
public ConnectionPoint inPoint ;
public ConnectionPoint outPoint ;
public GUIStyle style ;
public Node ( Vector2 position , float width , float height , GUIStyle nodeStyle , GUIStyle inPointStyle , GUIStyle outPointStyle , Action < ConnectionPoint > OnClickInPoint , Action < ConnectionPoint > OnClickOutPoint )
{
rect = new Rect ( position . x , position . y , width , height );
style = nodeStyle ;
inPoint = new ConnectionPoint ( this , ConnectionPointType . In , inPointStyle , OnClickInPoint );
outPoint = new ConnectionPoint ( this , ConnectionPointType . Out , outPointStyle , OnClickOutPoint );
}
public void Drag ( Vector2 delta )
{
rect . position += delta ;
}
public void Draw ()
{
inPoint . Draw ();
outPoint . Draw ();
GUI . Box ( rect , title , style );
}
public bool ProcessEvents ( Event e )
{
switch ( e . type )
{
case EventType . MouseDown :
if ( e . button == 0 )
{
if ( rect . Contains ( e . mousePosition ))
{
isDragged = true ;
GUI . changed = true ;
}
else
{
GUI . changed = true ;
}
}
break ;
case EventType . MouseUp :
isDragged = false ;
break ;
case EventType . MouseDrag :
if ( e . button == 0 && isDragged )
{
Drag ( e . delta );
e . Use ();
return true ;
}
break ;
}
return false ;
}
}
|
using UnityEngine ;
using UnityEditor ;
using System . Collections . Generic ;
public class NodeBasedEditor : EditorWindow
{
private List < Node > nodes ;
private List < Connection > connections ;
private GUIStyle nodeStyle ;
private GUIStyle inPointStyle ;
private GUIStyle outPointStyle ;
private ConnectionPoint selectedInPoint ;
private ConnectionPoint selectedOutPoint ;
[ MenuItem ( "Window/Node Based Editor" )]
private static void OpenWindow ()
{
NodeBasedEditor window = GetWindow < NodeBasedEditor > ();
window . titleContent = new GUIContent ( "Node Based Editor" );
}
private void OnEnable ()
{
nodeStyle = new GUIStyle ();
nodeStyle . normal . background = EditorGUIUtility . Load ( "builtin skins/darkskin/images/node1.png" ) as Texture2D ;
nodeStyle . border = new RectOffset ( 12 , 12 , 12 , 12 );
inPointStyle = new GUIStyle ();
inPointStyle . normal . background = EditorGUIUtility . Load ( "builtin skins/darkskin/images/btn left.png" ) as Texture2D ;
inPointStyle . active . background = EditorGUIUtility . Load ( "builtin skins/darkskin/images/btn left on.png" ) as Texture2D ;
inPointStyle . border = new RectOffset ( 4 , 4 , 12 , 12 );
outPointStyle = new GUIStyle ();
outPointStyle . normal . background = EditorGUIUtility . Load ( "builtin skins/darkskin/images/btn right.png" ) as Texture2D ;
outPointStyle . active . background = EditorGUIUtility . Load ( "builtin skins/darkskin/images/btn right on.png" ) as Texture2D ;
outPointStyle . border = new RectOffset ( 4 , 4 , 12 , 12 );
}
private void OnGUI ()
{
DrawNodes ();
DrawConnections ();
ProcessNodeEvents ( Event . current );
ProcessEvents ( Event . current );
if ( GUI . changed ) Repaint ();
}
private void DrawNodes ()
{
if ( nodes != null )
{
for ( int i = 0 ; i < nodes . Count ; i ++ )
{
nodes [ i ]. Draw ();
}
}
}
private void DrawConnections ()
{
if ( connections != null )
{
for ( int i = 0 ; i < connections . Count ; i ++ )
{
connections [ i ]. Draw ();
}
}
}
private void ProcessEvents ( Event e )
{
switch ( e . type )
{
case EventType . MouseDown :
if ( e . button == 0 )
{
ClearConnectionSelection ();
}
if ( e . button == 1 )
{
ProcessContextMenu ( e . mousePosition );
}
break ;
}
}
private void ProcessNodeEvents ( Event e )
{
if ( nodes != null )
{
for ( int i = nodes . Count - 1 ; i >= 0 ; i -- )
{
bool guiChanged = nodes [ i ]. ProcessEvents ( e );
if ( guiChanged )
{
GUI . changed = true ;
}
}
}
}
private void ProcessContextMenu ( Vector2 mousePosition )
{
GenericMenu genericMenu = new GenericMenu ();
genericMenu . AddItem ( new GUIContent ( "Add node" ), false , () => OnClickAddNode ( mousePosition ));
genericMenu . ShowAsContext ();
}
private void OnClickAddNode ( Vector2 mousePosition )
{
if ( nodes == null )
{
nodes = new List < Node > ();
}
nodes . Add ( new Node ( mousePosition , 200 , 50 , nodeStyle , inPointStyle , outPointStyle , OnClickInPoint , OnClickOutPoint ));
}
private void OnClickInPoint ( ConnectionPoint inPoint )
{
selectedInPoint = inPoint ;
if ( selectedOutPoint != null )
{
if ( selectedOutPoint . node != selectedInPoint . node )
{
CreateConnection ();
ClearConnectionSelection ();
}
else
{
ClearConnectionSelection ();
}
}
}
private void OnClickOutPoint ( ConnectionPoint outPoint )
{
selectedOutPoint = outPoint ;
if ( selectedInPoint != null )
{
if ( selectedOutPoint . node != selectedInPoint . node )
{
CreateConnection ();
ClearConnectionSelection ();
}
else
{
ClearConnectionSelection ();
}
}
}
private void OnClickRemoveConnection ( Connection connection )
{
connections . Remove ( connection );
}
private void CreateConnection ()
{
if ( connections == null )
{
connections = new List < Connection > ();
}
connections . Add ( new Connection ( selectedInPoint , selectedOutPoint , OnClickRemoveConnection ));
}
private void ClearConnectionSelection ()
{
selectedInPoint = null ;
selectedOutPoint = null ;
}
}
|
using System ;
using UnityEditor ;
using UnityEngine ;
public class Node
{
public Rect rect ;
public string title ;
public bool isDragged ;
public bool isSelected ;
public ConnectionPoint inPoint ;
public ConnectionPoint outPoint ;
public GUIStyle style ;
public GUIStyle defaultNodeStyle ;
public GUIStyle selectedNodeStyle ;
public Node ( Vector2 position , float width , float height , GUIStyle nodeStyle , GUIStyle selectedStyle , GUIStyle inPointStyle , GUIStyle outPointStyle , Action < ConnectionPoint > OnClickInPoint , Action < ConnectionPoint > OnClickOutPoint )
{
rect = new Rect ( position . x , position . y , width , height );
style = nodeStyle ;
inPoint = new ConnectionPoint ( this , ConnectionPointType . In , inPointStyle , OnClickInPoint );
outPoint = new ConnectionPoint ( this , ConnectionPointType . Out , outPointStyle , OnClickOutPoint );
defaultNodeStyle = nodeStyle ;
selectedNodeStyle = selectedStyle ;
}
public void Drag ( Vector2 delta )
{
rect . position += delta ;
}
public void Draw ()
{
inPoint . Draw ();
outPoint . Draw ();
GUI . Box ( rect , title , style );
}
public bool ProcessEvents ( Event e )
{
switch ( e . type )
{
case EventType . MouseDown :
if ( e . button == 0 )
{
if ( rect . Contains ( e . mousePosition ))
{
isDragged = true ;
GUI . changed = true ;
isSelected = true ;
style = selectedNodeStyle ;
}
else
{
GUI . changed = true ;
isSelected = false ;
style = defaultNodeStyle ;
}
}
break ;
case EventType . MouseUp :
isDragged = false ;
break ;
case EventType . MouseDrag :
if ( e . button == 0 && isDragged )
{
Drag ( e . delta );
e . Use ();
return true ;
}
break ;
}
return false ;
}
}
|
using UnityEngine ;
using UnityEditor ;
using System . Collections . Generic ;
public class NodeBasedEditor : EditorWindow
{
private List < Node > nodes ;
private List < Connection > connections ;
private GUIStyle nodeStyle ;
private GUIStyle selectedNodeStyle ;
private GUIStyle inPointStyle ;
private GUIStyle outPointStyle ;
private ConnectionPoint selectedInPoint ;
private ConnectionPoint selectedOutPoint ;
[ MenuItem ( "Window/Node Based Editor" )]
private static void OpenWindow ()
{
NodeBasedEditor window = GetWindow < NodeBasedEditor > ();
window . titleContent = new GUIContent ( "Node Based Editor" );
}
private void OnEnable ()
{
nodeStyle = new GUIStyle ();
nodeStyle . normal . background = EditorGUIUtility . Load ( "builtin skins/darkskin/images/node1.png" ) as Texture2D ;
nodeStyle . border = new RectOffset ( 12 , 12 , 12 , 12 );
selectedNodeStyle = new GUIStyle ();
selectedNodeStyle . normal . background = EditorGUIUtility . Load ( "builtin skins/darkskin/images/node1 on.png" ) as Texture2D ;
selectedNodeStyle . border = new RectOffset ( 12 , 12 , 12 , 12 );
inPointStyle = new GUIStyle ();
inPointStyle . normal . background = EditorGUIUtility . Load ( "builtin skins/darkskin/images/btn left.png" ) as Texture2D ;
inPointStyle . active . background = EditorGUIUtility . Load ( "builtin skins/darkskin/images/btn left on.png" ) as Texture2D ;
inPointStyle . border = new RectOffset ( 4 , 4 , 12 , 12 );
outPointStyle = new GUIStyle ();
outPointStyle . normal . background = EditorGUIUtility . Load ( "builtin skins/darkskin/images/btn right.png" ) as Texture2D ;
outPointStyle . active . background = EditorGUIUtility . Load ( "builtin skins/darkskin/images/btn right on.png" ) as Texture2D ;
outPointStyle . border = new RectOffset ( 4 , 4 , 12 , 12 );
}
...
|
private void OnClickAddNode ( Vector2 mousePosition )
{
if ( nodes == null )
{
nodes = new List < Node > ();
}
nodes . Add ( new Node ( mousePosition , 200 , 50 , nodeStyle , selectedNodeStyle , inPointStyle , outPointStyle , OnClickInPoint , OnClickOutPoint ));
}
|
using System ;
using UnityEditor ;
using UnityEngine ;
public class Node
{
public Rect rect ;
public string title ;
public bool isDragged ;
public bool isSelected ;
public ConnectionPoint inPoint ;
public ConnectionPoint outPoint ;
public GUIStyle style ;
public GUIStyle defaultNodeStyle ;
public GUIStyle selectedNodeStyle ;
public Action < Node > OnRemoveNode ;
public Node ( Vector2 position , float width , float height , GUIStyle nodeStyle , GUIStyle selectedStyle , GUIStyle inPointStyle , GUIStyle outPointStyle , Action < ConnectionPoint > OnClickInPoint , Action < ConnectionPoint > OnClickOutPoint , Action < Node > OnClickRemoveNode )
{
rect = new Rect ( position . x , position . y , width , height );
style = nodeStyle ;
inPoint = new ConnectionPoint ( this , ConnectionPointType . In , inPointStyle , OnClickInPoint );
outPoint = new ConnectionPoint ( this , ConnectionPointType . Out , outPointStyle , OnClickOutPoint );
defaultNodeStyle = nodeStyle ;
selectedNodeStyle = selectedStyle ;
OnRemoveNode = OnClickRemoveNode ;
}
public void Drag ( Vector2 delta )
{
rect . position += delta ;
}
public void Draw ()
{
inPoint . Draw ();
outPoint . Draw ();
GUI . Box ( rect , title , style );
}
public bool ProcessEvents ( Event e )
{
switch ( e . type )
{
case EventType . MouseDown :
if ( e . button == 0 )
{
if ( rect . Contains ( e . mousePosition ))
{
isDragged = true ;
GUI . changed = true ;
isSelected = true ;
style = selectedNodeStyle ;
}
else
{
GUI . changed = true ;
isSelected = false ;
style = defaultNodeStyle ;
}
}
if ( e . button == 1 && isSelected && rect . Contains ( e . mousePosition ))
{
ProcessContextMenu ();
e . Use ();
}
break ;
case EventType . MouseUp :
isDragged = false ;
break ;
case EventType . MouseDrag :
if ( e . button == 0 && isDragged )
{
Drag ( e . delta );
e . Use ();
return true ;
}
break ;
}
return false ;
}
private void ProcessContextMenu ()
{
GenericMenu genericMenu = new GenericMenu ();
genericMenu . AddItem ( new GUIContent ( "Remove node" ), false , OnClickRemoveNode );
genericMenu . ShowAsContext ();
}
private void OnClickRemoveNode ()
{
if ( OnRemoveNode != null )
{
OnRemoveNode ( this );
}
}
}
|
private void OnClickAddNode ( Vector2 mousePosition )
{
if ( nodes == null )
{
nodes = new List < Node > ();
}
nodes . Add ( new Node ( mousePosition , 200 , 50 , nodeStyle , selectedNodeStyle , inPointStyle , outPointStyle , OnClickInPoint , OnClickOutPoint , OnClickRemoveNode ));
}
|
private void OnClickRemoveNode ( Node node )
{
if ( connections != null )
{
List < Connection > connectionsToRemove = new List < Connection > ();
for ( int i = 0 ; i < connections . Count ; i ++ )
{
if ( connections [ i ]. inPoint == node . inPoint || connections [ i ]. outPoint == node . outPoint )
{
connectionsToRemove . Add ( connections [ i ]);
}
}
for ( int i = 0 ; i < connectionsToRemove . Count ; i ++ )
{
connections . Remove ( connectionsToRemove [ i ]);
}
connectionsToRemove = null ;
}
nodes . Remove ( node );
}
|
- 可拖动的画布,
- 从所选连接点到鼠标位置的贝塞尔曲线,
- 背景中的网格。
- 让我们的画布可以拖动是最简单的,所以让我们从这个开始。 我们所要做的只是将鼠标拖放到节点列表中的每个节点。
public class NodeBasedEditor : EditorWindow
{
private List < Node > nodes ;
private List < Connection > connections ;
private GUIStyle nodeStyle ;
private GUIStyle selectedNodeStyle ;
private GUIStyle inPointStyle ;
private GUIStyle outPointStyle ;
private ConnectionPoint selectedInPoint ;
private ConnectionPoint selectedOutPoint ;
private Vector2 drag ;
...
|
private void ProcessEvents ( Event e )
{
drag = Vector2 . zero ;
switch ( e . type )
{
case EventType . MouseDown :
if ( e . button == 0 )
{
ClearConnectionSelection ();
}
if ( e . button == 1 )
{
ProcessContextMenu ( e . mousePosition );
}
break ;
case EventType . MouseDrag :
if ( e . button == 0 )
{
OnDrag ( e . delta );
}
break ;
}
}
|
private void OnDrag ( Vector2 delta )
{
drag = delta ;
if ( nodes != null )
{
for ( int i = 0 ; i < nodes . Count ; i ++ )
{
nodes [ i ]. Drag ( delta );
}
}
GUI . changed = true ;
}
|
private void OnGUI ()
{
DrawNodes ();
DrawConnections ();
DrawConnectionLine ( Event . current );
ProcessNodeEvents ( Event . current );
ProcessEvents ( Event . current );
if ( GUI . changed ) Repaint ();
}
|
private void DrawConnectionLine ( Event e )
{
if ( selectedInPoint != null && selectedOutPoint == null )
{
Handles . DrawBezier (
selectedInPoint . rect . center ,
e . mousePosition ,
selectedInPoint . rect . center + Vector2 . left * 50f ,
e . mousePosition - Vector2 . left * 50f ,
Color . white ,
null ,
2f
);
GUI . changed = true ;
}
if ( selectedOutPoint != null && selectedInPoint == null )
{
Handles . DrawBezier (
selectedOutPoint . rect . center ,
e . mousePosition ,
selectedOutPoint . rect . center - Vector2 . left * 50f ,
e . mousePosition + Vector2 . left * 50f ,
Color . white ,
null ,
2f
);
GUI . changed = true ;
}
}
|
public class NodeBasedEditor : EditorWindow
{
private List < Node > nodes ;
private List < Connection > connections ;
private GUIStyle nodeStyle ;
private GUIStyle selectedNodeStyle ;
private GUIStyle inPointStyle ;
private GUIStyle outPointStyle ;
private ConnectionPoint selectedInPoint ;
private ConnectionPoint selectedOutPoint ;
private Vector2 offset ;
private Vector2 drag ;
...
|
private void OnGUI ()
{
DrawGrid ( 20 , 0.2f , Color . gray );
DrawGrid ( 100 , 0.4f , Color . gray );
DrawNodes ();
DrawConnections ();
DrawConnectionLine ( Event . current );
ProcessNodeEvents ( Event . current );
ProcessEvents ( Event . current );
if ( GUI . changed ) Repaint ();
}
private void DrawGrid ( float gridSpacing , float gridOpacity , Color gridColor )
{
int widthDivs = Mathf . CeilToInt ( position . width / gridSpacing );
int heightDivs = Mathf . CeilToInt ( position . height / gridSpacing );
Handles . BeginGUI ();
Handles . color = new Color ( gridColor . r , gridColor . g , gridColor . b , gridOpacity );
offset += drag * 0.5f ;
Vector3 newOffset = new Vector3 ( offset . x % gridSpacing , offset . y % gridSpacing , 0 );
for ( int i = 0 ; i < widthDivs ; i ++ )
{
Handles . DrawLine ( new Vector3 ( gridSpacing * i , - gridSpacing , 0 ) + newOffset , new Vector3 ( gridSpacing * i , position . height , 0f ) + newOffset );
}
for ( int j = 0 ; j < heightDivs ; j ++ )
{
Handles . DrawLine ( new Vector3 ( - gridSpacing , gridSpacing * j , 0 ) + newOffset , new Vector3 ( position . width , gridSpacing * j , 0f ) + newOffset );
}
Handles . color = Color . white ;
Handles . EndGUI ();
}
|
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
public class NodeBasedEditor : EditorWindow
{
private List<Node> nodes;
private List<Connection> connections;
private GUIStyle nodeStyle;
private GUIStyle selectedNodeStyle;
private GUIStyle inPointStyle;
private GUIStyle outPointStyle;
private ConnectionPoint selectedInPoint;
private ConnectionPoint selectedOutPoint;
private Vector2 offset;
private Vector2 drag;
[MenuItem("Window/Node Based Editor")]
private static void OpenWindow()
{
NodeBasedEditor window = GetWindow<NodeBasedEditor>();
window.titleContent = new GUIContent("Node Based Editor");
}
private void OnEnable()
{
nodeStyle = new GUIStyle();
nodeStyle.normal.background = EditorGUIUtility.Load("builtin skins/darkskin/images/node1.png") as Texture2D;
nodeStyle.border = new RectOffset(12, 12, 12, 12);
selectedNodeStyle = new GUIStyle();
selectedNodeStyle.normal.background = EditorGUIUtility.Load("builtin skins/darkskin/images/node1 on.png") as Texture2D;
selectedNodeStyle.border = new RectOffset(12, 12, 12, 12);
inPointStyle = new GUIStyle();
inPointStyle.normal.background = EditorGUIUtility.Load("builtin skins/darkskin/images/btn left.png") as Texture2D;
inPointStyle.active.background = EditorGUIUtility.Load("builtin skins/darkskin/images/btn left on.png") as Texture2D;
inPointStyle.border = new RectOffset(4, 4, 12, 12);
outPointStyle = new GUIStyle();
outPointStyle.normal.background = EditorGUIUtility.Load("builtin skins/darkskin/images/btn right.png") as Texture2D;
outPointStyle.active.background = EditorGUIUtility.Load("builtin skins/darkskin/images/btn right on.png") as Texture2D;
outPointStyle.border = new RectOffset(4, 4, 12, 12);
}
private void OnGUI()
{
DrawGrid(20, 0.2f, Color.gray);
DrawGrid(100, 0.4f, Color.gray);
DrawNodes();
DrawConnections();
DrawConnectionLine(Event.current);
ProcessNodeEvents(Event.current);
ProcessEvents(Event.current);
if (GUI.changed) Repaint();
}
private void DrawGrid(float gridSpacing, float gridOpacity, Color gridColor)
{
int widthDivs = Mathf.CeilToInt(position.width / gridSpacing);
int heightDivs = Mathf.CeilToInt(position.height / gridSpacing);
Handles.BeginGUI();
Handles.color = new Color(gridColor.r, gridColor.g, gridColor.b, gridOpacity);
offset += drag * 0.5f;
Vector3 newOffset = new Vector3(offset.x % gridSpacing, offset.y % gridSpacing, 0);
for (int i = 0; i < widthDivs; i++)
{
Handles.DrawLine(new Vector3(gridSpacing * i, -gridSpacing, 0) + newOffset, new Vector3(gridSpacing * i, position.height, 0f) + newOffset);
}
for (int j = 0; j < heightDivs; j++)
{
Handles.DrawLine(new Vector3(-gridSpacing, gridSpacing * j, 0) + newOffset, new Vector3(position.width, gridSpacing * j, 0f) + newOffset);
}
Handles.color = Color.white;
Handles.EndGUI();
}
private void DrawNodes()
{
if (nodes != null)
{
for (int i = 0; i < nodes.Count; i++)
{
nodes[i].Draw();
}
}
}
private void DrawConnections()
{
if (connections != null)
{
for (int i = 0; i < connections.Count; i++)
{
connections[i].Draw();
}
}
}
private void ProcessEvents(Event e)
{
drag = Vector2.zero;
switch (e.type)
{
case EventType.MouseDown:
if (e.button == 0)
{
ClearConnectionSelection();
}
if (e.button == 1)
{
ProcessContextMenu(e.mousePosition);
}
break;
case EventType.MouseDrag:
if (e.button == 0)
{
OnDrag(e.delta);
}
break;
}
}
private void ProcessNodeEvents(Event e)
{
if (nodes != null)
{
for (int i = nodes.Count - 1; i >= 0; i--)
{
bool guiChanged = nodes[i].ProcessEvents(e);
if (guiChanged)
{
GUI.changed = true;
}
}
}
}
private void DrawConnectionLine(Event e)
{
if (selectedInPoint != null && selectedOutPoint == null)
{
Handles.DrawBezier(
selectedInPoint.rect.center,
e.mousePosition,
selectedInPoint.rect.center + Vector2.left * 50f,
e.mousePosition - Vector2.left * 50f,
Color.white,
null,
2f
);
GUI.changed = true;
}
if (selectedOutPoint != null && selectedInPoint == null)
{
Handles.DrawBezier(
selectedOutPoint.rect.center,
e.mousePosition,
selectedOutPoint.rect.center - Vector2.left * 50f,
e.mousePosition + Vector2.left * 50f,
Color.white,
null,
2f
);
GUI.changed = true;
}
}
private void ProcessContextMenu(Vector2 mousePosition)
{
GenericMenu genericMenu = new GenericMenu();
genericMenu.AddItem(new GUIContent("Add node"), false, () => OnClickAddNode(mousePosition));
genericMenu.ShowAsContext();
}
private void OnDrag(Vector2 delta)
{
drag = delta;
if (nodes != null)
{
for (int i = 0; i < nodes.Count; i++)
{
nodes[i].Drag(delta);
}
}
GUI.changed = true;
}
private void OnClickAddNode(Vector2 mousePosition)
{
if (nodes == null)
{
nodes = new List<Node>();
}
nodes.Add(new Node(mousePosition, 200, 50, nodeStyle, selectedNodeStyle, inPointStyle, outPointStyle, OnClickInPoint, OnClickOutPoint, OnClickRemoveNode));
}
private void OnClickInPoint(ConnectionPoint inPoint)
{
selectedInPoint = inPoint;
if (selectedOutPoint != null)
{
if (selectedOutPoint.node != selectedInPoint.node)
{
CreateConnection();
ClearConnectionSelection();
}
else
{
ClearConnectionSelection();
}
}
}
private void OnClickOutPoint(ConnectionPoint outPoint)
{
selectedOutPoint = outPoint;
if (selectedInPoint != null)
{
if (selectedOutPoint.node != selectedInPoint.node)
{
CreateConnection();
ClearConnectionSelection();
}
else
{
ClearConnectionSelection();
}
}
}
private void OnClickRemoveNode(Node node)
{
if (connections != null)
{
List<Connection> connectionsToRemove = new List<Connection>();
for (int i = 0; i < connections.Count; i++)
{
if (connections[i].inPoint == node.inPoint || connections[i].outPoint == node.outPoint)
{
connectionsToRemove.Add(connections[i]);
}
}
for (int i = 0; i < connectionsToRemove.Count; i++)
{
connections.Remove(connectionsToRemove[i]);
}
connectionsToRemove = null;
}
nodes.Remove(node);
}
private void OnClickRemoveConnection(Connection connection)
{
connections.Remove(connection);
}
private void CreateConnection()
{
if (connections == null)
{
connections = new List<Connection>();
}
connections.Add(new Connection(selectedInPoint, selectedOutPoint, OnClickRemoveConnection));
}
private void ClearConnectionSelection()
{
selectedInPoint = null;
selectedOutPoint = null;
}
}
|
using System;
using UnityEditor;
using UnityEngine;
public class Node
{
public Rect rect;
public string title;
public bool isDragged;
public bool isSelected;
public ConnectionPoint inPoint;
public ConnectionPoint outPoint;
public GUIStyle style;
public GUIStyle defaultNodeStyle;
public GUIStyle selectedNodeStyle;
public Action<Node> OnRemoveNode;
public Node(Vector2 position, float width, float height, GUIStyle nodeStyle, GUIStyle selectedStyle, GUIStyle inPointStyle, GUIStyle outPointStyle, Action<ConnectionPoint> OnClickInPoint, Action<ConnectionPoint> OnClickOutPoint, Action<Node> OnClickRemoveNode)
{
rect = new Rect(position.x, position.y, width, height);
style = nodeStyle;
inPoint = new ConnectionPoint(this, ConnectionPointType.In, inPointStyle, OnClickInPoint);
outPoint = new ConnectionPoint(this, ConnectionPointType.Out, outPointStyle, OnClickOutPoint);
defaultNodeStyle = nodeStyle;
selectedNodeStyle = selectedStyle;
OnRemoveNode = OnClickRemoveNode;
}
public void Drag(Vector2 delta)
{
rect.position += delta;
}
public void Draw()
{
inPoint.Draw();
outPoint.Draw();
GUI.Box(rect, title, style);
}
public bool ProcessEvents(Event e)
{
switch (e.type)
{
case EventType.MouseDown:
if (e.button == 0)
{
if (rect.Contains(e.mousePosition))
{
isDragged = true;
GUI.changed = true;
isSelected = true;
style = selectedNodeStyle;
}
else
{
GUI.changed = true;
isSelected = false;
style = defaultNodeStyle;
}
}
if (e.button == 1 && isSelected && rect.Contains(e.mousePosition))
{
ProcessContextMenu();
e.Use();
}
break;
case EventType.MouseUp:
isDragged = false;
break;
case EventType.MouseDrag:
if (e.button == 0 && isDragged)
{
Drag(e.delta);
e.Use();
return true;
}
break;
}
return false;
}
private void ProcessContextMenu()
{
GenericMenu genericMenu = new GenericMenu();
genericMenu.AddItem(new GUIContent("Remove node"), false, OnClickRemoveNode);
genericMenu.ShowAsContext();
}
private void OnClickRemoveNode()
{
if (OnRemoveNode != null)
{
OnRemoveNode(this);
}
}
}
|
using System;
using UnityEditor;
using UnityEngine;
public class Connection
{
public ConnectionPoint inPoint;
public ConnectionPoint outPoint;
public Action<Connection> OnClickRemoveConnection;
public Connection(ConnectionPoint inPoint, ConnectionPoint outPoint, Action<Connection> OnClickRemoveConnection)
{
this.inPoint = inPoint;
this.outPoint = outPoint;
this.OnClickRemoveConnection = OnClickRemoveConnection;
}
public void Draw()
{
Handles.DrawBezier(
inPoint.rect.center,
outPoint.rect.center,
inPoint.rect.center + Vector2.left * 50f,
outPoint.rect.center - Vector2.left * 50f,
Color.white,
null,
2f
);
if (Handles.Button((inPoint.rect.center + outPoint.rect.center) * 0.5f, Quaternion.identity, 4, 8, Handles.RectangleCap))
{
if (OnClickRemoveConnection != null)
{
OnClickRemoveConnection(this);
}
}
}
}
|
using System;
using UnityEngine;
public enum ConnectionPointType { In, Out }
public class ConnectionPoint
{
public Rect rect;
public ConnectionPointType type;
public Node node;
public GUIStyle style;
public Action<ConnectionPoint> OnClickConnectionPoint;
public ConnectionPoint(Node node, ConnectionPointType type, GUIStyle style, Action<ConnectionPoint> OnClickConnectionPoint)
{
this.node = node;
this.type = type;
this.style = style;
this.OnClickConnectionPoint = OnClickConnectionPoint;
rect = new Rect(0, 0, 10f, 20f);
}
public void Draw()
{
rect.y = node.rect.y + (node.rect.height * 0.5f) - rect.height * 0.5f;
switch (type)
{
case ConnectionPointType.In:
rect.x = node.rect.x - rect.width + 8f;
break;
case ConnectionPointType.Out:
rect.x = node.rect.x + node.rect.width - 8f;
break;
}
if (GUI.Button(rect, "", style))
{
if (OnClickConnectionPoint != null)
{
OnClickConnectionPoint(this);
}
}
}
}
|
在Unity中创建基于Node节点的编辑器 (一)相关推荐
- 在Unity中创建基于Node节点的编辑器 (二) 窗口序列化
孙广东 2018.5.13 csdn 的产品 , 真垃圾, 不想吐槽了, 文章保存就丢! 没办法 . 怎么不满意, 还是得继续用, 哎~~~ 第二部分 在Unity中序列化基于节点的 ...
- 学习在Unity中创建一个动作RPG游戏
游戏开发变得简单.使用Unity学习C#并创建您自己的动作角色扮演游戏! 你会学到什么 学习C#,一种现代通用的编程语言. 了解Unity中2D发展的能力. 发展强大的和可移植的解决问题的技能. 了解 ...
- 学习用C#在Unity中创建一个2D Metroidvania游戏
学习用C#在Unity中创建一个2D Metroidvania游戏 你会学到: 构建2D Unity游戏 用C#编程 玩家统计,水平提升,米尔和远程攻击 敌方人工智能系统 制定级别和级别选择 Lear ...
- 学会在Unity中创建一个Match-3益智游戏 Learn To Create a Match-3 Puzzle Game in Unity
MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz,2 Ch 语言:英语+中英文字幕(根据原英文字幕机译更准确) |时长:48场讲座(6h 38m) |大小解压后:2.8 G ...
- Unity中创建本地多人游戏完整案例视频教程 Learn To Create A Local Multiplayer Game In Unity
Unity中创建本地多人游戏完整案例视频教程 Learn To Create A Local Multiplayer Game In Unity MP4 |视频:h264,1280x720 |音频:A ...
- unity中创建游戏场景_在Unity中创建Beat Em Up游戏
unity中创建游戏场景 Learn how to use Unity to create a 3D Beat Em Up game in this full tutorial from Awesom ...
- 在Unity中实现基于粒子的水模拟(二:开始着色)
在Unity中实现基于粒子的水模拟(二:开始着色) 文章目录 在Unity中实现基于粒子的水模拟(二:开始着色) 前言 一.生成顶点 二.偏移模拟 1.接收细分着色器输出的顶点 2.根据数据调用对应的 ...
- 在Unity中实现基于粒子的水模拟(三:混合屏幕)
在Unity中实现基于粒子的水模拟(三:混合屏幕) 文章目录 在Unity中实现基于粒子的水模拟(三:混合屏幕) 前言 一.着色算法介绍 1.折射 2.反射 二.准备纹理 1.获取纹理 2.模糊纹理 ...
- Revit中创建基于线的砌体墙及【快速砌体排砖】
墙可以更改内部结构和材质,但是很难画出砌块样式形成的墙体,我们可以用其他方式画出砌体排砖墙么?这里我们用基于线的常规模型做砌体排砖墙.在开始我们需要做两个族,作为砌体排砖墙的基本单位,也就是一个单 ...
最新文章
- 压力测试对于BCH真的有意义吗?
- react-flux单向数据流
- 如何从Docker容器内部连接到计算机的本地主机?
- Ubuntu平台 Qt 5.x 安装方法
- Java学习必不可少的网站,快收藏起来!
- Mysql 图像二进制保存-Blocb、TinyBlob、MediumBlob、LongBlob
- VS高版本编写C程序的C4996错误
- linq 分组求和的一般方法
- python的环境变量设置
- Android系统 (150)---Android 开发者工具
- security工作笔记009---spring security BCryptPasswordEncoder加密解密,不错的随机盐,不错的加密解密方法
- 大剧播出无人值守“心里不慌”,优酷全链路技术齐上阵
- Ubuntu下安装Nginx服务器并进行优化
- singleTop对onActivityForResult的影响
- 华为软件开发云又出新服务:开源镜像站正式上线,致敬开源,使能开发者!
- 软件工程--需求分析的任务详解
- kafka log4j日志级别修改,一天生成一个日志文件
- ICMP协议与ping
- 关于地理数据收集与处理的基本工具推荐(3)--最新30m的DEM与DSM数据免费下载
- 积极心理学第十九课 如何让爱情天长地久
热门文章
- 阿里巴巴中台战略思想和架构 整理而成的思维导图,你值得拥有
- 成人大专和全日制大专的区别在哪里
- 受亚马逊、微软青睐 Bespin Global 获上亿A轮融资,君联资本领投
- 如何用手机登录企业邮箱?微信如何绑定邮箱账号?
- 英语6级复习的好资料
- linux内核对nsm配置,H3C SecPath系列安全产品 NSQM1NSM 单板手册(V1.02)
- 中国大学moocpython程序设计答案_中国大学慕课moocPython编程基础章节测试答案
- crossover mac好用吗 mac用crossover损害电脑吗
- 五百年一遇的时代变革,“元宇宙”将成为时代制高点
- 三、支付宝支付对接 - 申请、配置、签约、获取RSkey(1)