孙广东 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
);
}
}
}
}
|
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
private List
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
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
}
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
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
}
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
public Node(Vector2 position, float width, float height, GUIStyle nodeStyle, GUIStyle selectedStyle, GUIStyle inPointStyle, GUIStyle outPointStyle, Action
{
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
public Connection(ConnectionPoint inPoint, ConnectionPoint outPoint, Action
{
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
public ConnectionPoint(Node node, ConnectionPointType type, GUIStyle style, Action
{
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);
}
}
}
}
|