diff --git a/Example/ExampleNodeGraph.asset b/Example/ExampleNodeGraph.asset index 3818860..16e79ec 100644 Binary files a/Example/ExampleNodeGraph.asset and b/Example/ExampleNodeGraph.asset differ diff --git a/Example/Nodes/DisplayValue.cs b/Example/Nodes/DisplayValue.cs new file mode 100644 index 0000000..01a2b0f --- /dev/null +++ b/Example/Nodes/DisplayValue.cs @@ -0,0 +1,5 @@ +using UnityEngine; + +public class DisplayValue : Node { + [Input] public float value; +} diff --git a/Example/Nodes/DisplayValue.cs.meta b/Example/Nodes/DisplayValue.cs.meta new file mode 100644 index 0000000..aa380ea --- /dev/null +++ b/Example/Nodes/DisplayValue.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 98f6f901f0da53142b79277ea3f42518 +timeCreated: 1507499149 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example/Nodes/Editor/DisplayValueEditor.cs b/Example/Nodes/Editor/DisplayValueEditor.cs new file mode 100644 index 0000000..b0f4643 --- /dev/null +++ b/Example/Nodes/Editor/DisplayValueEditor.cs @@ -0,0 +1,32 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +[CustomNodeEditor(typeof(DisplayValue), "Display Value")] +public class DisplayValueEditor : NodeEditor { + + public override void OnNodeGUI(out Dictionary portPositions) { + base.OnNodeGUI(out portPositions); + EditorGUILayout.LabelField("Value: " + GetResult()); + } + + public float GetResult() { + float result = 0f; + NodePort port = target.GetInputByFieldName("value"); + if (port == null) return result; + int connectionCount = port.ConnectionCount; + for (int i = 0; i < connectionCount; i++) { + + NodePort connection = port.GetConnection(i); + if (connection == null) continue; + + object obj = connection.GetValue(); + if (obj == null) continue; + + if (connection.type == typeof(int)) result += (int)obj; + else if (connection.type == typeof(float)) result += (float)obj; + } + return result; + } +} diff --git a/Example/Nodes/Editor/DisplayValueEditor.cs.meta b/Example/Nodes/Editor/DisplayValueEditor.cs.meta new file mode 100644 index 0000000..15cde80 --- /dev/null +++ b/Example/Nodes/Editor/DisplayValueEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 429e0671aa9024e449642837aeadc9c2 +timeCreated: 1507499229 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example/Nodes/MathNode.cs b/Example/Nodes/MathNode.cs index b9a9d27..32aa322 100644 --- a/Example/Nodes/MathNode.cs +++ b/Example/Nodes/MathNode.cs @@ -2,8 +2,8 @@ [System.Serializable] public class MathNode : Node { - [Input] public float a; - [Input] public float b; + public float a; + public float b; [Output] public float result; public enum MathType { Add, Subtract, Multiply, Divide} public MathType mathType = MathType.Add; @@ -12,6 +12,20 @@ public class MathNode : Node { name = "Math"; } + public override object GetValue(NodePort port) { + switch(port.fieldName) { + case "result": + switch(mathType) { + case MathType.Add: return a + b; + case MathType.Subtract: return a - b; + case MathType.Multiply: return a * b; + case MathType.Divide: return a / b; + } + break; + } + return 0f; + } + public override void OnCreateConnection(NodePort from, NodePort to) { } diff --git a/Scripts/Editor/NodeEditor.cs b/Scripts/Editor/NodeEditor.cs index 25e600a..c2c20d2 100644 --- a/Scripts/Editor/NodeEditor.cs +++ b/Scripts/Editor/NodeEditor.cs @@ -58,7 +58,6 @@ public class NodeEditor { if (NodeEditorUtilities.HasAttrib(fieldAttribs) || NodeEditorUtilities.HasAttrib(fieldAttribs)) continue; DrawFieldInfoDrawerGUI(fields[i]); } - EditorGUILayout.Space(); } /// Draw node port GUI using automatic layouting. Returns port handle position. diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs index 9b473ba..cf0c44e 100644 --- a/Scripts/Editor/NodeEditorGUI.cs +++ b/Scripts/Editor/NodeEditorGUI.cs @@ -167,6 +167,8 @@ public partial class NodeEditorWindow { //Draw node contents Dictionary portHandlePoints; nodeEditor.OnNodeGUI(out portHandlePoints); + EditorGUILayout.Space(); + if (e.type == EventType.Repaint) { foreach (var kvp in portHandlePoints) { Vector2 portHandlePos = kvp.Value; diff --git a/Scripts/Node.cs b/Scripts/Node.cs index 1963d3b..49f62d0 100644 --- a/Scripts/Node.cs +++ b/Scripts/Node.cs @@ -1,6 +1,7 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; +using System.Linq; using System; /// Base class for all nodes @@ -13,16 +14,18 @@ public abstract class Node : ScriptableObject { /// Input s. It is recommended not to modify these at hand. Instead, see [SerializeField] public List inputs = new List(); /// Output s. It is recommended not to modify these at hand. Instead, see - [SerializeField] public NodePort[] outputs = new NodePort[0]; + [SerializeField] public List outputs = new List(); public int InputCount { get { return inputs.Count; } } - public int OutputCount { get { return outputs.Length; } } + public int OutputCount { get { return outputs.Count; } } protected Node() { CachePorts(); //Cache the ports at creation time so we don't have to use reflection at runtime } protected void OnEnable() { + VerifyConnections(); + CachePorts(); Init(); } @@ -49,6 +52,7 @@ public abstract class Node : ScriptableObject { for (int i = 0; i < OutputCount; i++) { if (outputs[i].fieldName == fieldName) return outputs[i]; } + Debug.LogWarning("No outputs with fieldName '" + fieldName+"'"); return null; } @@ -57,6 +61,12 @@ public abstract class Node : ScriptableObject { for (int i = 0; i < InputCount; i++) { if (inputs[i].fieldName == fieldName) return inputs[i]; } + Debug.LogWarning("No inputs with fieldName '" + fieldName+"'"); + return null; + } + + public virtual object GetValue(NodePort port) { + Debug.LogWarning("No GetValue(NodePort port) override defined for " + GetType()); return null; } @@ -75,7 +85,7 @@ public abstract class Node : ScriptableObject { return -1; } public int GetOutputId(NodePort output) { - for (int i = 0; i < outputs.Length; i++) { + for (int i = 0; i < outputs.Count; i++) { if (output == outputs[i]) return i; } @@ -86,7 +96,7 @@ public abstract class Node : ScriptableObject { for (int i = 0; i < inputs.Count; i++) { inputs[i].ClearConnections(); } - for (int i = 0; i < outputs.Length; i++) { + for (int i = 0; i < outputs.Count; i++) { outputs[i].ClearConnections(); } } @@ -114,6 +124,7 @@ public abstract class Node : ScriptableObject { System.Reflection.FieldInfo[] fieldInfo = GetType().GetFields(); for (int i = 0; i < fieldInfo.Length; i++) { + //Get InputAttribute and OutputAttribute object[] attribs = fieldInfo[i].GetCustomAttributes(false); InputAttribute inputAttrib = null; @@ -122,12 +133,29 @@ public abstract class Node : ScriptableObject { if (attribs[k] is InputAttribute) inputAttrib = attribs[k] as InputAttribute; else if (attribs[k] is OutputAttribute) outputAttrib = attribs[k] as OutputAttribute; } + if (inputAttrib != null && outputAttrib != null) Debug.LogError("Field " + fieldInfo + " cannot be both input and output."); else if (inputAttrib != null) inputPorts.Add(new NodePort(fieldInfo[i], this)); else if (outputAttrib != null) outputPorts.Add(new NodePort(fieldInfo[i], this)); } - inputs = inputPorts; - outputs = outputPorts.ToArray(); + //Remove + for (int i = inputs.Count-1; i >= 0; i--) { + //If input nodeport does not exist, remove it + if (!inputPorts.Any(x => inputs[i].fieldName == x.fieldName)) inputs.RemoveAt(i); + } + for (int i = outputs.Count - 1; i >= 0; i--) { + //If output nodeport does not exist, remove it + if (!outputPorts.Any(x => outputs[i].fieldName == x.fieldName)) outputs.RemoveAt(i); + } + //Add + for (int i = 0; i < inputPorts.Count; i++) { + //If inputports contains a new port, add it + if (!inputs.Any(x => x.fieldName == inputPorts[i].fieldName)) inputs.Add(inputPorts[i]); + } + for (int i = 0; i < outputPorts.Count; i++) { + //If inputports contains a new port, add it + if (!outputs.Any(x => x.fieldName == outputPorts[i].fieldName)) outputs.Add(outputPorts[i]); + } } } diff --git a/Scripts/NodePort.cs b/Scripts/NodePort.cs index e3d5451..dfef17c 100644 --- a/Scripts/NodePort.cs +++ b/Scripts/NodePort.cs @@ -55,6 +55,10 @@ public class NodePort { } } + public object GetValue() { + return node.GetValue(this); + } + /// Connect this to another /// The to connect to public void Connect(NodePort port) {