diff --git a/Examples/NodeToy/NodeGraphExample.asset b/Examples/NodeToy/NodeGraphExample.asset
index d703c11..595fa1a 100644
Binary files a/Examples/NodeToy/NodeGraphExample.asset and b/Examples/NodeToy/NodeGraphExample.asset differ
diff --git a/Examples/NodeToy/NodeGraphExample.asset.meta b/Examples/NodeToy/NodeGraphExample.asset.meta
index e7e9fda..1af7b94 100644
--- a/Examples/NodeToy/NodeGraphExample.asset.meta
+++ b/Examples/NodeToy/NodeGraphExample.asset.meta
@@ -1,6 +1,6 @@
fileFormatVersion: 2
-guid: 84fbc8acdc9656941b529a16e8bbe318
-timeCreated: 1506462197
+guid: 2e27fbb85ccd5994e932fd8a6d34e4b3
+timeCreated: 1506790922
licenseType: Free
NativeFormatImporter:
mainObjectFileID: 11400000
diff --git a/Examples/NodeToy/MathToyNodeGraph.cs b/Examples/NodeToy/NodeGraphExample.cs
similarity index 62%
rename from Examples/NodeToy/MathToyNodeGraph.cs
rename to Examples/NodeToy/NodeGraphExample.cs
index 8f89aa0..0d38514 100644
--- a/Examples/NodeToy/MathToyNodeGraph.cs
+++ b/Examples/NodeToy/NodeGraphExample.cs
@@ -1,9 +1,8 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
-
+using System;
/// Defines an example nodegraph.
-[CreateAssetMenu(fileName = "NodeGraphExample", menuName = "Node Graph/Example")]
+[Serializable, CreateAssetMenu(fileName = "NodeGraphExample", menuName = "Node Graph/Example")]
public class NodeGraphExample : NodeGraph {
-
}
diff --git a/Examples/NodeToy/MathToyNodeGraph.cs.meta b/Examples/NodeToy/NodeGraphExample.cs.meta
similarity index 100%
rename from Examples/NodeToy/MathToyNodeGraph.cs.meta
rename to Examples/NodeToy/NodeGraphExample.cs.meta
diff --git a/Examples/Nodes/Editor/MathNodeEditor.cs b/Examples/Nodes/Editor/MathNodeEditor.cs
index 7dbc033..1cca50a 100644
--- a/Examples/Nodes/Editor/MathNodeEditor.cs
+++ b/Examples/Nodes/Editor/MathNodeEditor.cs
@@ -1,7 +1,10 @@
-[CustomNodeEditor(typeof(MathNode), "Math")]
+using System.Collections.Generic;
+using UnityEngine;
+
+[CustomNodeEditor(typeof(MathNode), "Math")]
public class AddNodeEditor : NodeEditor {
- public override void OnNodeGUI() {
- base.OnNodeGUI();
+ public override void OnNodeGUI(out Dictionary portPositions) {
+ base.OnNodeGUI(out portPositions);
}
}
diff --git a/Scripts/Editor/NodeEditor.cs b/Scripts/Editor/NodeEditor.cs
index 6d825a6..312ec3c 100644
--- a/Scripts/Editor/NodeEditor.cs
+++ b/Scripts/Editor/NodeEditor.cs
@@ -8,17 +8,18 @@ using System;
/// Base class to derive custom Node editors from. Use this to create your own custom inspectors and editors for your nodes.
public class NodeEditor {
- public Dictionary portRects = new Dictionary();
public Node target;
- public virtual void OnNodeGUI() {
- portRects.Clear();
- DrawDefaultNodePortsGUI();
+ /// Draws the node GUI.
+ /// Port handle positions need to be returned to the NodeEditorWindow
+ public virtual void OnNodeGUI(out Dictionary portPositions) {
+ DrawDefaultNodePortsGUI(out portPositions);
DrawDefaultNodeBodyGUI();
}
/// Draws standard editors for all fields marked with or
- protected void DrawDefaultNodePortsGUI() {
+ protected void DrawDefaultNodePortsGUI(out Dictionary portPositions) {
+ portPositions = new Dictionary();
Event e = Event.current;
@@ -27,14 +28,16 @@ public class NodeEditor {
//Inputs
GUILayout.BeginVertical();
for (int i = 0; i < target.InputCount; i++) {
- DrawNodePortGUI(target.inputs[i]);
+ Vector2 handlePoint = DrawNodePortGUI(target.inputs[i]);
+ portPositions.Add(target.inputs[i], handlePoint);
}
GUILayout.EndVertical();
//Outputs
GUILayout.BeginVertical();
for (int i = 0; i < target.OutputCount; i++) {
- DrawNodePortGUI(target.outputs[i]);
+ Vector2 handlePoint = DrawNodePortGUI(target.outputs[i]);
+ portPositions.Add(target.outputs[i], handlePoint);
}
GUILayout.EndVertical();
@@ -52,31 +55,25 @@ public class NodeEditor {
EditorGUILayout.Space();
}
- protected void DrawNodePortGUI(NodePort port) {
+ /// Draw node port GUI using automatic layouting. Returns port handle position.
+ protected Vector2 DrawNodePortGUI(NodePort port) {
GUIStyle style = port.direction == NodePort.IO.Input ? NodeEditorResources.styles.inputStyle : NodeEditorResources.styles.outputStyle;
Rect rect = GUILayoutUtility.GetRect(new GUIContent(port.name.PrettifyCamelCase()), style);
- DrawNodePortGUI(rect, port);
+ return DrawNodePortGUI(rect, port);
}
- protected void DrawNodePortGUI(Rect rect, NodePort port) {
+ /// Draw node port GUI in rect. Returns port handle position.
+ protected Vector2 DrawNodePortGUI(Rect rect, NodePort port) {
GUIStyle style = port.direction == NodePort.IO.Input ? NodeEditorResources.styles.inputStyle : NodeEditorResources.styles.outputStyle;
GUI.Label(rect, new GUIContent(port.name.PrettifyCamelCase()), style);
- Rect handleRect = new Rect(0, 0, 16, 16);
+
+ Vector2 handlePoint = rect.center;
+
switch (port.direction) {
- case NodePort.IO.Input:
- handleRect.position = new Vector2(rect.xMin - 8, rect.position.y + (rect.height * 0.5f) - 8);
- break;
- case NodePort.IO.Output:
- handleRect.position = new Vector2(rect.xMax - 8, rect.position.y + (rect.height * 0.5f) - 8);
- break;
+ case NodePort.IO.Input: handlePoint.x = rect.xMin; break;
+ case NodePort.IO.Output: handlePoint.x = rect.xMax; break;
}
- portRects.Add(port, handleRect);
- Color col = GUI.color;
- GUI.color = NodeEditorUtilities.GetTypeColor(port.type);
- GUI.DrawTexture(handleRect, NodeEditorResources.dot);
- GUI.color = new Color(0.29f,0.31f,0.32f);
- GUI.DrawTexture(handleRect, NodeEditorResources.dotOuter);
- GUI.color = col;
+ return handlePoint;
}
private static FieldInfo[] GetInspectorFields(Node node) {
diff --git a/Scripts/Editor/NodeEditorAction.cs b/Scripts/Editor/NodeEditorAction.cs
index 9c85df8..0868684 100644
--- a/Scripts/Editor/NodeEditorAction.cs
+++ b/Scripts/Editor/NodeEditorAction.cs
@@ -129,8 +129,8 @@ public partial class NodeEditorWindow {
public void DrawDraggedConnection() {
if (IsDraggingPort) {
if (!_portConnectionPoints.ContainsKey(draggedOutput)) return;
- Vector2 from = draggedOutput.node.rect.position + _portConnectionPoints[draggedOutput].center;
- Vector2 to = draggedOutputTarget != null ? draggedOutputTarget.node.rect.position + portConnectionPoints[draggedOutputTarget].center : WindowToGridPosition(Event.current.mousePosition);
+ Vector2 from = _portConnectionPoints[draggedOutput].center;
+ Vector2 to = draggedOutputTarget != null ? portConnectionPoints[draggedOutputTarget].center : WindowToGridPosition(Event.current.mousePosition);
Color col = NodeEditorUtilities.GetTypeColor(draggedOutput.type);
col.a = 0.6f;
DrawConnection(from, to, col);
@@ -154,33 +154,29 @@ public partial class NodeEditorWindow {
Repaint();
}
//If we are hovering a node, check if we are also hovering a port
- if (IsHoveringNode) {
- NodePort newHoverPort = null;
- //Check all input ports
- for (int i = 0; i < hoveredNode.InputCount; i++) {
- NodePort port = hoveredNode.inputs[i];
+ NodePort newHoverPort = null;
+ //Check all input ports
+ for (int k = 0; k < graph.nodes.Count; k++) {
+
+ for (int i = 0; i < graph.nodes[k].InputCount; i++) {
+ NodePort port = graph.nodes[k].inputs[i];
//Check if port rect is available
if (!portConnectionPoints.ContainsKey(port)) continue;
- Rect r = portConnectionPoints[port];
- r.position = GridToWindowPosition(r.position + hoveredNode.rect.position);
- r.size /= zoom;
+ Rect r = GridToWindowRect(portConnectionPoints[port]);
if (r.Contains(mousePos)) newHoverPort = port;
}
//Check all output ports
- for (int i = 0; i < hoveredNode.OutputCount; i++) {
- NodePort port = hoveredNode.outputs[i];
+ for (int i = 0; i < graph.nodes[k].OutputCount; i++) {
+ NodePort port = graph.nodes[k].outputs[i];
//Check if port rect is available
if (!portConnectionPoints.ContainsKey(port)) continue;
- Rect r = portConnectionPoints[port];
- r.position = GridToWindowPosition(r.position + hoveredNode.rect.position);
- r.size /= zoom;
+ Rect r = GridToWindowRect(portConnectionPoints[port]);
if (r.Contains(mousePos)) newHoverPort = port;
}
- if (newHoverPort != hoveredPort) {
- hoveredPort = newHoverPort;
- }
}
- else hoveredPort = null;
+ if (newHoverPort != hoveredPort) {
+ hoveredPort = newHoverPort;
+ }
}
bool IsHoveringTitle(Node node) {
diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs
index b52c26c..4aff684 100644
--- a/Scripts/Editor/NodeEditorGUI.cs
+++ b/Scripts/Editor/NodeEditorGUI.cs
@@ -1,6 +1,7 @@
using UnityEngine;
using UnityEditor;
using System;
+using System.Collections.Generic;
/// Contains GUI methods
public partial class NodeEditorWindow {
@@ -14,6 +15,7 @@ public partial class NodeEditorWindow {
DrawNodes();
DrawConnections();
DrawDraggedConnection();
+ DrawPortHandles();
DrawToolbar();
GUI.matrix = m;
@@ -117,6 +119,7 @@ public partial class NodeEditorWindow {
GUI.color = prevCol;
}
+ /// Draws all connections
public void DrawConnections() {
foreach (Node node in graph.nodes) {
for (int i = 0; i < node.OutputCount; i++) {
@@ -124,16 +127,30 @@ public partial class NodeEditorWindow {
//Needs cleanup. Null checks are ugly
if (!portConnectionPoints.ContainsKey(output)) continue;
- Vector2 from = _portConnectionPoints[output].center + node.rect.position;
+ Vector2 from = _portConnectionPoints[output].center;
for (int k = 0; k < output.ConnectionCount; k++) {
NodePort input = output.GetConnection(k);
- Vector2 to = input.node.rect.position + _portConnectionPoints[input].center;
+ Vector2 to = _portConnectionPoints[input].center;
DrawConnection(from, to, NodeEditorUtilities.GetTypeColor(output.type));
}
}
}
}
+ /// Draws the draggable circle handles on the ports
+ public void DrawPortHandles() {
+ Color col = GUI.color;
+ foreach(var kvp in portConnectionPoints) {
+ Rect rect = GridToWindowRect(kvp.Value);
+ GUI.color = new Color(0.29f, 0.31f, 0.32f);
+ GUI.DrawTexture(rect, NodeEditorResources.dotOuter);
+ GUI.color = NodeEditorUtilities.GetTypeColor(kvp.Key.type);
+ GUI.DrawTexture(rect, NodeEditorResources.dot);
+
+ }
+ GUI.color = col;
+ }
+
private void DrawNodes() {
Event e = Event.current;
if (e.type == EventType.Repaint) portConnectionPoints.Clear();
@@ -164,10 +181,14 @@ public partial class NodeEditorWindow {
nodeEditor.target = node;
- nodeEditor.OnNodeGUI();
+ Dictionary portHandlePoints;
+ nodeEditor.OnNodeGUI(out portHandlePoints);
if (e.type == EventType.Repaint) {
- foreach (var kvp in nodeEditor.portRects) {
- portConnectionPoints.Add(kvp.Key, kvp.Value);
+ foreach (var kvp in portHandlePoints) {
+ Vector2 portHandlePos = kvp.Value;
+ portHandlePos += node.rect.position;
+ Rect rect = new Rect(portHandlePos.x - 8, portHandlePos.y - 8, 16, 16);
+ portConnectionPoints.Add(kvp.Key, rect);
}
}
diff --git a/Scripts/Editor/NodeEditorWindow.cs b/Scripts/Editor/NodeEditorWindow.cs
index 13f1f5f..71bb640 100644
--- a/Scripts/Editor/NodeEditorWindow.cs
+++ b/Scripts/Editor/NodeEditorWindow.cs
@@ -7,15 +7,16 @@ using UnityEditor.Callbacks;
using System;
[InitializeOnLoad]
-public partial class NodeEditorWindow : EditorWindow {
+public partial class NodeEditorWindow : EditorWindow {
+ /// Stores node positions for all nodePorts.
public Dictionary portConnectionPoints { get { return _portConnectionPoints; } }
private Dictionary _portConnectionPoints = new Dictionary();
- public NodeGraph graph { get { return _graph != null ? _graph : _graph = CreateInstance(); } }
- public NodeGraph _graph;
+ public NodeGraph graph;
public Vector2 panOffset { get { return _panOffset; } set { _panOffset = value; Repaint(); } }
private Vector2 _panOffset;
public float zoom { get { return _zoom; } set { _zoom = Mathf.Clamp(value, 1f, 5f); Repaint(); } }
- private float _zoom = 1;
+ private float _zoom = 1;
+
partial void OnEnable();
/// Create editor window
@@ -29,8 +30,8 @@ public partial class NodeEditorWindow : EditorWindow {
}
public void Save() {
- if (AssetDatabase.Contains(_graph)) {
- EditorUtility.SetDirty(_graph);
+ if (AssetDatabase.Contains(graph)) {
+ EditorUtility.SetDirty(graph);
AssetDatabase.SaveAssets();
}
else SaveAs();
@@ -42,8 +43,8 @@ public partial class NodeEditorWindow : EditorWindow {
else {
NodeGraph existingGraph = AssetDatabase.LoadAssetAtPath(path);
if (existingGraph != null) AssetDatabase.DeleteAsset(path);
- AssetDatabase.CreateAsset(_graph, path);
- EditorUtility.SetDirty(_graph);
+ AssetDatabase.CreateAsset(graph, path);
+ EditorUtility.SetDirty(graph);
AssetDatabase.SaveAssets();
}
}
@@ -60,6 +61,12 @@ public partial class NodeEditorWindow : EditorWindow {
return (position.size * 0.5f) + (panOffset / zoom) + (gridPosition/zoom);
}
+ public Rect GridToWindowRect(Rect gridRect) {
+ gridRect.position = GridToWindowPosition(gridRect.position);
+ gridRect.size /= zoom;
+ return gridRect;
+ }
+
public Vector2 GridToWindowPositionNoClipped(Vector2 gridPosition) {
Vector2 center = position.size * 0.5f;
float xOffset = (center.x * zoom + (panOffset.x + gridPosition.x));
@@ -71,12 +78,13 @@ public partial class NodeEditorWindow : EditorWindow {
selectedNode = node;
}
+
[OnOpenAsset(0)]
public static bool OnOpen(int instanceID, int line) {
NodeGraph nodeGraph = EditorUtility.InstanceIDToObject(instanceID) as NodeGraph;
if (nodeGraph != null) {
NodeEditorWindow w = Init();
- w._graph = nodeGraph;
+ w.graph = nodeGraph;
return true;
}
return false;
diff --git a/Scripts/NodeGraph.cs b/Scripts/NodeGraph.cs
index c8cf56c..128add7 100644
--- a/Scripts/NodeGraph.cs
+++ b/Scripts/NodeGraph.cs
@@ -4,13 +4,11 @@ using UnityEngine;
using System;
/// Base class for all node graphs
+[Serializable]
public abstract class NodeGraph : ScriptableObject {
/// All nodes in the graph.
/// See:
- [NonSerialized] public List nodes = new List();
-
- /// Serialized nodes.
- [SerializeField] public string[] s_nodes;
+ [SerializeField] public List nodes = new List();
public T AddNode() where T : Node {
return AddNode(typeof(T)) as T;