mirror of
https://github.com/Siccity/xNode.git
synced 2026-02-14 02:58:45 +08:00
Connections now draw under port handles
Modulized code. Too many minor changes to address
This commit is contained in:
parent
f8a0bb8f7c
commit
6a92f18618
Binary file not shown.
@ -1,6 +1,6 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 84fbc8acdc9656941b529a16e8bbe318
|
guid: 2e27fbb85ccd5994e932fd8a6d34e4b3
|
||||||
timeCreated: 1506462197
|
timeCreated: 1506790922
|
||||||
licenseType: Free
|
licenseType: Free
|
||||||
NativeFormatImporter:
|
NativeFormatImporter:
|
||||||
mainObjectFileID: 11400000
|
mainObjectFileID: 11400000
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using System;
|
||||||
/// <summary> Defines an example nodegraph. </summary>
|
/// <summary> Defines an example nodegraph. </summary>
|
||||||
[CreateAssetMenu(fileName = "NodeGraphExample", menuName = "Node Graph/Example")]
|
[Serializable, CreateAssetMenu(fileName = "NodeGraphExample", menuName = "Node Graph/Example")]
|
||||||
public class NodeGraphExample : NodeGraph {
|
public class NodeGraphExample : NodeGraph {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,7 +1,10 @@
|
|||||||
[CustomNodeEditor(typeof(MathNode), "Math")]
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
[CustomNodeEditor(typeof(MathNode), "Math")]
|
||||||
public class AddNodeEditor : NodeEditor {
|
public class AddNodeEditor : NodeEditor {
|
||||||
|
|
||||||
public override void OnNodeGUI() {
|
public override void OnNodeGUI(out Dictionary<NodePort, Vector2> portPositions) {
|
||||||
base.OnNodeGUI();
|
base.OnNodeGUI(out portPositions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,17 +8,18 @@ using System;
|
|||||||
/// <summary> Base class to derive custom Node editors from. Use this to create your own custom inspectors and editors for your nodes. </summary>
|
/// <summary> Base class to derive custom Node editors from. Use this to create your own custom inspectors and editors for your nodes. </summary>
|
||||||
public class NodeEditor {
|
public class NodeEditor {
|
||||||
|
|
||||||
public Dictionary<NodePort, Rect> portRects = new Dictionary<NodePort, Rect>();
|
|
||||||
public Node target;
|
public Node target;
|
||||||
|
|
||||||
public virtual void OnNodeGUI() {
|
/// <summary> Draws the node GUI.</summary>
|
||||||
portRects.Clear();
|
/// <param name="portPositions">Port handle positions need to be returned to the NodeEditorWindow </param>
|
||||||
DrawDefaultNodePortsGUI();
|
public virtual void OnNodeGUI(out Dictionary<NodePort,Vector2> portPositions) {
|
||||||
|
DrawDefaultNodePortsGUI(out portPositions);
|
||||||
DrawDefaultNodeBodyGUI();
|
DrawDefaultNodeBodyGUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Draws standard editors for all fields marked with <see cref="Node.InputAttribute"/> or <see cref="Node.OutputAttribute"/> </summary>
|
/// <summary> Draws standard editors for all fields marked with <see cref="Node.InputAttribute"/> or <see cref="Node.OutputAttribute"/> </summary>
|
||||||
protected void DrawDefaultNodePortsGUI() {
|
protected void DrawDefaultNodePortsGUI(out Dictionary<NodePort, Vector2> portPositions) {
|
||||||
|
portPositions = new Dictionary<NodePort, Vector2>();
|
||||||
|
|
||||||
Event e = Event.current;
|
Event e = Event.current;
|
||||||
|
|
||||||
@ -27,14 +28,16 @@ public class NodeEditor {
|
|||||||
//Inputs
|
//Inputs
|
||||||
GUILayout.BeginVertical();
|
GUILayout.BeginVertical();
|
||||||
for (int i = 0; i < target.InputCount; i++) {
|
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();
|
GUILayout.EndVertical();
|
||||||
|
|
||||||
//Outputs
|
//Outputs
|
||||||
GUILayout.BeginVertical();
|
GUILayout.BeginVertical();
|
||||||
for (int i = 0; i < target.OutputCount; i++) {
|
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();
|
GUILayout.EndVertical();
|
||||||
|
|
||||||
@ -52,31 +55,25 @@ public class NodeEditor {
|
|||||||
EditorGUILayout.Space();
|
EditorGUILayout.Space();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void DrawNodePortGUI(NodePort port) {
|
/// <summary> Draw node port GUI using automatic layouting. Returns port handle position. </summary>
|
||||||
|
protected Vector2 DrawNodePortGUI(NodePort port) {
|
||||||
GUIStyle style = port.direction == NodePort.IO.Input ? NodeEditorResources.styles.inputStyle : NodeEditorResources.styles.outputStyle;
|
GUIStyle style = port.direction == NodePort.IO.Input ? NodeEditorResources.styles.inputStyle : NodeEditorResources.styles.outputStyle;
|
||||||
Rect rect = GUILayoutUtility.GetRect(new GUIContent(port.name.PrettifyCamelCase()), style);
|
Rect rect = GUILayoutUtility.GetRect(new GUIContent(port.name.PrettifyCamelCase()), style);
|
||||||
DrawNodePortGUI(rect, port);
|
return DrawNodePortGUI(rect, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void DrawNodePortGUI(Rect rect, NodePort port) {
|
/// <summary> Draw node port GUI in rect. Returns port handle position. </summary>
|
||||||
|
protected Vector2 DrawNodePortGUI(Rect rect, NodePort port) {
|
||||||
GUIStyle style = port.direction == NodePort.IO.Input ? NodeEditorResources.styles.inputStyle : NodeEditorResources.styles.outputStyle;
|
GUIStyle style = port.direction == NodePort.IO.Input ? NodeEditorResources.styles.inputStyle : NodeEditorResources.styles.outputStyle;
|
||||||
GUI.Label(rect, new GUIContent(port.name.PrettifyCamelCase()), style);
|
GUI.Label(rect, new GUIContent(port.name.PrettifyCamelCase()), style);
|
||||||
Rect handleRect = new Rect(0, 0, 16, 16);
|
|
||||||
|
Vector2 handlePoint = rect.center;
|
||||||
|
|
||||||
switch (port.direction) {
|
switch (port.direction) {
|
||||||
case NodePort.IO.Input:
|
case NodePort.IO.Input: handlePoint.x = rect.xMin; break;
|
||||||
handleRect.position = new Vector2(rect.xMin - 8, rect.position.y + (rect.height * 0.5f) - 8);
|
case NodePort.IO.Output: handlePoint.x = rect.xMax; break;
|
||||||
break;
|
|
||||||
case NodePort.IO.Output:
|
|
||||||
handleRect.position = new Vector2(rect.xMax - 8, rect.position.y + (rect.height * 0.5f) - 8);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
portRects.Add(port, handleRect);
|
return handlePoint;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FieldInfo[] GetInspectorFields(Node node) {
|
private static FieldInfo[] GetInspectorFields(Node node) {
|
||||||
|
|||||||
@ -129,8 +129,8 @@ public partial class NodeEditorWindow {
|
|||||||
public void DrawDraggedConnection() {
|
public void DrawDraggedConnection() {
|
||||||
if (IsDraggingPort) {
|
if (IsDraggingPort) {
|
||||||
if (!_portConnectionPoints.ContainsKey(draggedOutput)) return;
|
if (!_portConnectionPoints.ContainsKey(draggedOutput)) return;
|
||||||
Vector2 from = draggedOutput.node.rect.position + _portConnectionPoints[draggedOutput].center;
|
Vector2 from = _portConnectionPoints[draggedOutput].center;
|
||||||
Vector2 to = draggedOutputTarget != null ? draggedOutputTarget.node.rect.position + portConnectionPoints[draggedOutputTarget].center : WindowToGridPosition(Event.current.mousePosition);
|
Vector2 to = draggedOutputTarget != null ? portConnectionPoints[draggedOutputTarget].center : WindowToGridPosition(Event.current.mousePosition);
|
||||||
Color col = NodeEditorUtilities.GetTypeColor(draggedOutput.type);
|
Color col = NodeEditorUtilities.GetTypeColor(draggedOutput.type);
|
||||||
col.a = 0.6f;
|
col.a = 0.6f;
|
||||||
DrawConnection(from, to, col);
|
DrawConnection(from, to, col);
|
||||||
@ -154,33 +154,29 @@ public partial class NodeEditorWindow {
|
|||||||
Repaint();
|
Repaint();
|
||||||
}
|
}
|
||||||
//If we are hovering a node, check if we are also hovering a port
|
//If we are hovering a node, check if we are also hovering a port
|
||||||
if (IsHoveringNode) {
|
NodePort newHoverPort = null;
|
||||||
NodePort newHoverPort = null;
|
//Check all input ports
|
||||||
//Check all input ports
|
for (int k = 0; k < graph.nodes.Count; k++) {
|
||||||
for (int i = 0; i < hoveredNode.InputCount; i++) {
|
|
||||||
NodePort port = hoveredNode.inputs[i];
|
for (int i = 0; i < graph.nodes[k].InputCount; i++) {
|
||||||
|
NodePort port = graph.nodes[k].inputs[i];
|
||||||
//Check if port rect is available
|
//Check if port rect is available
|
||||||
if (!portConnectionPoints.ContainsKey(port)) continue;
|
if (!portConnectionPoints.ContainsKey(port)) continue;
|
||||||
Rect r = portConnectionPoints[port];
|
Rect r = GridToWindowRect(portConnectionPoints[port]);
|
||||||
r.position = GridToWindowPosition(r.position + hoveredNode.rect.position);
|
|
||||||
r.size /= zoom;
|
|
||||||
if (r.Contains(mousePos)) newHoverPort = port;
|
if (r.Contains(mousePos)) newHoverPort = port;
|
||||||
}
|
}
|
||||||
//Check all output ports
|
//Check all output ports
|
||||||
for (int i = 0; i < hoveredNode.OutputCount; i++) {
|
for (int i = 0; i < graph.nodes[k].OutputCount; i++) {
|
||||||
NodePort port = hoveredNode.outputs[i];
|
NodePort port = graph.nodes[k].outputs[i];
|
||||||
//Check if port rect is available
|
//Check if port rect is available
|
||||||
if (!portConnectionPoints.ContainsKey(port)) continue;
|
if (!portConnectionPoints.ContainsKey(port)) continue;
|
||||||
Rect r = portConnectionPoints[port];
|
Rect r = GridToWindowRect(portConnectionPoints[port]);
|
||||||
r.position = GridToWindowPosition(r.position + hoveredNode.rect.position);
|
|
||||||
r.size /= zoom;
|
|
||||||
if (r.Contains(mousePos)) newHoverPort = port;
|
if (r.Contains(mousePos)) newHoverPort = port;
|
||||||
}
|
}
|
||||||
if (newHoverPort != hoveredPort) {
|
|
||||||
hoveredPort = newHoverPort;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else hoveredPort = null;
|
if (newHoverPort != hoveredPort) {
|
||||||
|
hoveredPort = newHoverPort;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsHoveringTitle(Node node) {
|
bool IsHoveringTitle(Node node) {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
/// <summary> Contains GUI methods </summary>
|
/// <summary> Contains GUI methods </summary>
|
||||||
public partial class NodeEditorWindow {
|
public partial class NodeEditorWindow {
|
||||||
@ -14,6 +15,7 @@ public partial class NodeEditorWindow {
|
|||||||
DrawNodes();
|
DrawNodes();
|
||||||
DrawConnections();
|
DrawConnections();
|
||||||
DrawDraggedConnection();
|
DrawDraggedConnection();
|
||||||
|
DrawPortHandles();
|
||||||
DrawToolbar();
|
DrawToolbar();
|
||||||
|
|
||||||
GUI.matrix = m;
|
GUI.matrix = m;
|
||||||
@ -117,6 +119,7 @@ public partial class NodeEditorWindow {
|
|||||||
GUI.color = prevCol;
|
GUI.color = prevCol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Draws all connections </summary>
|
||||||
public void DrawConnections() {
|
public void DrawConnections() {
|
||||||
foreach (Node node in graph.nodes) {
|
foreach (Node node in graph.nodes) {
|
||||||
for (int i = 0; i < node.OutputCount; i++) {
|
for (int i = 0; i < node.OutputCount; i++) {
|
||||||
@ -124,16 +127,30 @@ public partial class NodeEditorWindow {
|
|||||||
|
|
||||||
//Needs cleanup. Null checks are ugly
|
//Needs cleanup. Null checks are ugly
|
||||||
if (!portConnectionPoints.ContainsKey(output)) continue;
|
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++) {
|
for (int k = 0; k < output.ConnectionCount; k++) {
|
||||||
NodePort input = output.GetConnection(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));
|
DrawConnection(from, to, NodeEditorUtilities.GetTypeColor(output.type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Draws the draggable circle handles on the ports </summary>
|
||||||
|
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() {
|
private void DrawNodes() {
|
||||||
Event e = Event.current;
|
Event e = Event.current;
|
||||||
if (e.type == EventType.Repaint) portConnectionPoints.Clear();
|
if (e.type == EventType.Repaint) portConnectionPoints.Clear();
|
||||||
@ -164,10 +181,14 @@ public partial class NodeEditorWindow {
|
|||||||
|
|
||||||
nodeEditor.target = node;
|
nodeEditor.target = node;
|
||||||
|
|
||||||
nodeEditor.OnNodeGUI();
|
Dictionary<NodePort, Vector2> portHandlePoints;
|
||||||
|
nodeEditor.OnNodeGUI(out portHandlePoints);
|
||||||
if (e.type == EventType.Repaint) {
|
if (e.type == EventType.Repaint) {
|
||||||
foreach (var kvp in nodeEditor.portRects) {
|
foreach (var kvp in portHandlePoints) {
|
||||||
portConnectionPoints.Add(kvp.Key, kvp.Value);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,15 +7,16 @@ using UnityEditor.Callbacks;
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
[InitializeOnLoad]
|
[InitializeOnLoad]
|
||||||
public partial class NodeEditorWindow : EditorWindow {
|
public partial class NodeEditorWindow : EditorWindow {
|
||||||
|
/// <summary> Stores node positions for all nodePorts. </summary>
|
||||||
public Dictionary<NodePort, Rect> portConnectionPoints { get { return _portConnectionPoints; } }
|
public Dictionary<NodePort, Rect> portConnectionPoints { get { return _portConnectionPoints; } }
|
||||||
private Dictionary<NodePort, Rect> _portConnectionPoints = new Dictionary<NodePort, Rect>();
|
private Dictionary<NodePort, Rect> _portConnectionPoints = new Dictionary<NodePort, Rect>();
|
||||||
public NodeGraph graph { get { return _graph != null ? _graph : _graph = CreateInstance<NodeGraph>(); } }
|
public NodeGraph graph;
|
||||||
public NodeGraph _graph;
|
|
||||||
public Vector2 panOffset { get { return _panOffset; } set { _panOffset = value; Repaint(); } }
|
public Vector2 panOffset { get { return _panOffset; } set { _panOffset = value; Repaint(); } }
|
||||||
private Vector2 _panOffset;
|
private Vector2 _panOffset;
|
||||||
public float zoom { get { return _zoom; } set { _zoom = Mathf.Clamp(value, 1f, 5f); Repaint(); } }
|
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();
|
partial void OnEnable();
|
||||||
/// <summary> Create editor window </summary>
|
/// <summary> Create editor window </summary>
|
||||||
@ -29,8 +30,8 @@ public partial class NodeEditorWindow : EditorWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void Save() {
|
public void Save() {
|
||||||
if (AssetDatabase.Contains(_graph)) {
|
if (AssetDatabase.Contains(graph)) {
|
||||||
EditorUtility.SetDirty(_graph);
|
EditorUtility.SetDirty(graph);
|
||||||
AssetDatabase.SaveAssets();
|
AssetDatabase.SaveAssets();
|
||||||
}
|
}
|
||||||
else SaveAs();
|
else SaveAs();
|
||||||
@ -42,8 +43,8 @@ public partial class NodeEditorWindow : EditorWindow {
|
|||||||
else {
|
else {
|
||||||
NodeGraph existingGraph = AssetDatabase.LoadAssetAtPath<NodeGraph>(path);
|
NodeGraph existingGraph = AssetDatabase.LoadAssetAtPath<NodeGraph>(path);
|
||||||
if (existingGraph != null) AssetDatabase.DeleteAsset(path);
|
if (existingGraph != null) AssetDatabase.DeleteAsset(path);
|
||||||
AssetDatabase.CreateAsset(_graph, path);
|
AssetDatabase.CreateAsset(graph, path);
|
||||||
EditorUtility.SetDirty(_graph);
|
EditorUtility.SetDirty(graph);
|
||||||
AssetDatabase.SaveAssets();
|
AssetDatabase.SaveAssets();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,6 +61,12 @@ public partial class NodeEditorWindow : EditorWindow {
|
|||||||
return (position.size * 0.5f) + (panOffset / zoom) + (gridPosition/zoom);
|
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) {
|
public Vector2 GridToWindowPositionNoClipped(Vector2 gridPosition) {
|
||||||
Vector2 center = position.size * 0.5f;
|
Vector2 center = position.size * 0.5f;
|
||||||
float xOffset = (center.x * zoom + (panOffset.x + gridPosition.x));
|
float xOffset = (center.x * zoom + (panOffset.x + gridPosition.x));
|
||||||
@ -71,12 +78,13 @@ public partial class NodeEditorWindow : EditorWindow {
|
|||||||
selectedNode = node;
|
selectedNode = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[OnOpenAsset(0)]
|
[OnOpenAsset(0)]
|
||||||
public static bool OnOpen(int instanceID, int line) {
|
public static bool OnOpen(int instanceID, int line) {
|
||||||
NodeGraph nodeGraph = EditorUtility.InstanceIDToObject(instanceID) as NodeGraph;
|
NodeGraph nodeGraph = EditorUtility.InstanceIDToObject(instanceID) as NodeGraph;
|
||||||
if (nodeGraph != null) {
|
if (nodeGraph != null) {
|
||||||
NodeEditorWindow w = Init();
|
NodeEditorWindow w = Init();
|
||||||
w._graph = nodeGraph;
|
w.graph = nodeGraph;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -4,13 +4,11 @@ using UnityEngine;
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
/// <summary> Base class for all node graphs </summary>
|
/// <summary> Base class for all node graphs </summary>
|
||||||
|
[Serializable]
|
||||||
public abstract class NodeGraph : ScriptableObject {
|
public abstract class NodeGraph : ScriptableObject {
|
||||||
/// <summary> All nodes in the graph. <para/>
|
/// <summary> All nodes in the graph. <para/>
|
||||||
/// See: <see cref="AddNode{T}"/> </summary>
|
/// See: <see cref="AddNode{T}"/> </summary>
|
||||||
[NonSerialized] public List<Node> nodes = new List<Node>();
|
[SerializeField] public List<Node> nodes = new List<Node>();
|
||||||
|
|
||||||
/// <summary> Serialized nodes. </summary>
|
|
||||||
[SerializeField] public string[] s_nodes;
|
|
||||||
|
|
||||||
public T AddNode<T>() where T : Node {
|
public T AddNode<T>() where T : Node {
|
||||||
return AddNode(typeof(T)) as T;
|
return AddNode(typeof(T)) as T;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user