//$ Copyright 2015-22, Code Respawn Technologies Pvt Ltd - All Rights Reserved $// using UnityEngine; using System.Collections.Generic; namespace DungeonArchitect.Graphs { /// /// Represents a graph node in the theme graph. This is the base class for all graph nodes /// [System.Serializable] public class GraphNode : ScriptableObject { [SerializeField] [HideInInspector] protected string id; /// /// The ID of the graph node /// public string Id { get { return id; } set { id = value; } } [SerializeField] [HideInInspector] protected string caption; /// /// The caption label of the node. It is up to the implementation to draw this label, if needed /// public string Caption { get { return caption; } set { caption = value; } } [SerializeField] [HideInInspector] protected Rect bounds = new Rect(10, 10, 120, 120); /// /// The bounds of the node /// public Rect Bounds { get { return bounds; } set { bounds = value; } } [SerializeField] [HideInInspector] protected bool canBeDeleted = true; public bool CanBeDeleted { get { return canBeDeleted; } } [SerializeField] [HideInInspector] protected bool canBeSelected = true; public bool CanBeSelected { get { return canBeSelected; } } [SerializeField] [HideInInspector] protected bool canBeMoved = true; public bool CanBeMoved { get { return canBeMoved; } } [SerializeField] [HideInInspector] protected bool selected = false; /// /// Flag to indicate if the node has been selected /// public bool Selected { get { return selected; } set { if (canBeSelected) { selected = value; } else { selected = false; } } } /// /// The size of the node /// public Vector2 Size { get { return bounds.size; } set { bounds.size = value; } } /// /// The position of the node /// public Vector2 Position { get { return bounds.position; } set { bounds.position = value; } } [SerializeField] [HideInInspector] protected int zIndex; /// /// The Z-index of the node. It determines if the node is on top of other nodes /// public int ZIndex { get { return zIndex; } set { zIndex = value; } } [SerializeField] [HideInInspector] protected List inputPins; /// /// List of input pins owned by this node /// public GraphPin[] InputPins { get { return inputPins != null ? inputPins.ToArray() : new GraphPin[0]; } } [SerializeField] [HideInInspector] protected List outputPins; /// /// List of output pins owned by this node /// public GraphPin[] OutputPins { get { return outputPins != null ? outputPins.ToArray() : new GraphPin[0]; } } /// /// Gets the first output pin. Returns null if no output pins are defined /// public GraphPin OutputPin { get { if (outputPins == null || outputPins.Count == 0) return null; return outputPins[0]; } } /// /// Gets the first input pin. Returns null if no input pins are defined /// public GraphPin InputPin { get { if (inputPins == null || inputPins.Count == 0) return null; return inputPins[0]; } } [SerializeField] [HideInInspector] protected Graph graph; /// /// The graph that owns this node /// public Graph Graph { get { return graph; } } public virtual void OnEnable() { hideFlags = HideFlags.HideInHierarchy; } public virtual void Initialize(string id, Graph graph) { this.id = id; this.graph = graph; } /// /// Called when the node is copied. /// The implementations should implement copy here (e.g. deep / shallow copy depending on implementation) /// /// public virtual void CopyFrom(GraphNode node) { if (node != null) { caption = node.Caption; this.bounds = node.Bounds; } } protected void UpdateName(string prefix) { this.name = prefix + id; } private bool dragging = false; public bool Dragging { get { return dragging; } set { dragging = value; } } /// /// Creates a pin with the specified configuration /// /// The type of pin (input / output) /// The position of the pin, relative to the node bounds /// The bounds of the pin, relative to the position /// The tangent of the pin. Links connected to the pin would come out from this direction protected GraphPin CreatePin(GraphPinType pinType, Vector2 position, Rect boundsOffset, Vector2 tangent) { return CreatePinOfType(pinType, position, boundsOffset, tangent); } protected T CreatePinOfType(GraphPinType pinType, Vector2 position, Rect boundsOffset, Vector2 tangent) where T : GraphPin { var pin = CreateInstance(); pin.PinType = pinType; pin.Node = this; pin.Position = position; pin.BoundsOffset = boundsOffset; pin.Tangent = tangent; if (pinType == GraphPinType.Input) { pin.name = this.name + "_InputPin"; if (inputPins == null) { inputPins = new List(); } inputPins.Add(pin); } else { pin.name = this.name + "_OutputPin"; if (outputPins == null) { outputPins = new List(); } outputPins.Add(pin); } return pin; } /// /// Gets the list of parent graph nodes /// /// List of parent graph nodes public GraphNode[] GetParentNodes() { var parents = new List(); if (InputPins.Length > 0) { foreach (var link in InputPins[0].GetConntectedLinks()) { if (link != null && link.Output != null && link.Output.Node != null) { parents.Add(link.Output.Node); } } } return parents.ToArray(); } /// /// Gets the list of child nodes /// /// List of child nodes public GraphNode[] GetChildNodes() { var children = new List(); if (OutputPins.Length > 0) { foreach (var link in OutputPins[0].GetConntectedLinks()) { if (link != null && link.Input != null && link.Input.Node != null) { children.Add(link.Input.Node); } } } return children.ToArray(); } /// /// Moves the node by the specified delta /// /// The delta offset to move the node by public void DragNode(Vector2 delta) { Position += delta; } } }