using NodeCanvas.Framework; using ParadoxNotion; using UnityEngine; namespace NodeCanvas.StateMachines { /// Super base class for FSM nodes that live within an FSM Graph. public abstract class FSMNode : Node { public override bool allowAsPrime { get { return false; } } public override bool canSelfConnect { get { return false; } } public override int maxInConnections { get { return -1; } } public override int maxOutConnections { get { return -1; } } sealed public override System.Type outConnectionType { get { return typeof(FSMConnection); } } sealed public override Alignment2x2 commentsAlignment { get { return Alignment2x2.Bottom; } } sealed public override Alignment2x2 iconAlignment { get { return Alignment2x2.Bottom; } } ///The FSM this state belongs to public FSM FSM { get { return (FSM)graph; } } ///---------------------------------------------------------------------------------------------- ///---------------------------------------UNITY EDITOR------------------------------------------- #if UNITY_EDITOR private static GUIPort clickedPort { get; set; } private static int dragDropMisses { get; set; } class GUIPort { public FSMNode parent { get; private set; } public Vector2 pos { get; private set; } public GUIPort(FSMNode parent, Vector2 pos) { this.parent = parent; this.pos = pos; } } //Draw the ports and connections sealed protected override void DrawNodeConnections(Rect drawCanvas, bool fullDrawPass, Vector2 canvasMousePos, float zoomFactor) { var e = Event.current; //Receive connections first if ( clickedPort != null && e.type == EventType.MouseUp && e.button == 0 ) { if ( rect.Contains(e.mousePosition) ) { graph.ConnectNodes(clickedPort.parent, this); clickedPort = null; e.Use(); } else { dragDropMisses++; if ( dragDropMisses == graph.allNodes.Count && clickedPort != null ) { var source = clickedPort.parent; var pos = Event.current.mousePosition; var menu = new UnityEditor.GenericMenu(); clickedPort = null; menu.AddItem(new GUIContent("Add Action State"), false, () => { var newState = graph.AddNode(pos); graph.ConnectNodes(source, newState); }); //PostGUI cause of zoom factors Editor.GraphEditorUtility.PostGUI += () => { menu.ShowAsContext(); }; Event.current.Use(); e.Use(); } } } var portRectLeft = new Rect(0, 0, 20, 20); var portRectRight = new Rect(0, 0, 20, 20); var portRectBottom = new Rect(0, 0, 20, 20); portRectLeft.center = new Vector2(rect.x - 11, rect.center.y); portRectRight.center = new Vector2(rect.xMax + 11, rect.center.y); portRectBottom.center = new Vector2(rect.center.x, rect.yMax + 11); if ( maxOutConnections != 0 ) { if ( fullDrawPass || drawCanvas.Overlaps(rect) ) { UnityEditor.EditorGUIUtility.AddCursorRect(portRectLeft, UnityEditor.MouseCursor.ArrowPlus); UnityEditor.EditorGUIUtility.AddCursorRect(portRectRight, UnityEditor.MouseCursor.ArrowPlus); UnityEditor.EditorGUIUtility.AddCursorRect(portRectBottom, UnityEditor.MouseCursor.ArrowPlus); GUI.color = new Color(1, 1, 1, 0.3f); GUI.DrawTexture(portRectLeft, Editor.StyleSheet.arrowLeft); GUI.DrawTexture(portRectRight, Editor.StyleSheet.arrowRight); if ( maxInConnections == 0 ) { GUI.DrawTexture(portRectBottom, Editor.StyleSheet.arrowBottom); } GUI.color = Color.white; if ( Editor.GraphEditorUtility.allowClick && e.type == EventType.MouseDown && e.button == 0 ) { if ( portRectLeft.Contains(e.mousePosition) ) { clickedPort = new GUIPort(this, portRectLeft.center); dragDropMisses = 0; e.Use(); } if ( portRectRight.Contains(e.mousePosition) ) { clickedPort = new GUIPort(this, portRectRight.center); dragDropMisses = 0; e.Use(); } if ( maxInConnections == 0 && portRectBottom.Contains(e.mousePosition) ) { clickedPort = new GUIPort(this, portRectBottom.center); dragDropMisses = 0; e.Use(); } } } } //draw new linking if ( clickedPort != null && clickedPort.parent == this ) { UnityEditor.Handles.DrawBezier(clickedPort.pos, e.mousePosition, clickedPort.pos, e.mousePosition, new Color(0.5f, 0.5f, 0.8f, 0.8f), Editor.StyleSheet.bezierTexture, 2); } //draw out connections for ( var i = 0; i < outConnections.Count; i++ ) { var connection = outConnections[i] as FSMConnection; var targetState = connection.targetNode as FSMNode; if ( targetState == null ) { //In case of MissingNode type continue; } var targetPos = targetState.GetConnectedInPortPosition(connection); var sourcePos = Vector2.zero; if ( rect.center.x <= targetPos.x ) { sourcePos = portRectRight.center; } if ( rect.center.x > targetPos.x ) { sourcePos = portRectLeft.center; } if ( maxInConnections == 0 && rect.center.y < targetPos.y - 50 && Mathf.Abs(rect.center.x - targetPos.x) < 200 ) { sourcePos = portRectBottom.center; } var boundRect = RectUtils.GetBoundRect(sourcePos, targetPos); if ( fullDrawPass || drawCanvas.Overlaps(boundRect) ) { connection.DrawConnectionGUI(sourcePos, targetPos); } } } //... Vector2 GetConnectedInPortPosition(Connection connection) { var sourcePos = connection.sourceNode.rect.center; var thisPos = rect.center; var style = 0; if ( style == 0 ) { if ( sourcePos.x <= thisPos.x ) { if ( sourcePos.y <= thisPos.y ) { return new Vector2(rect.center.x - 15, rect.yMin - ( this == graph.primeNode ? 20 : 0 )); } else { return new Vector2(rect.center.x - 15, rect.yMax + 2); } } if ( sourcePos.x > thisPos.x ) { if ( sourcePos.y <= thisPos.y ) { return new Vector2(rect.center.x + 15, rect.yMin - ( this == graph.primeNode ? 20 : 0 )); } else { return new Vector2(rect.center.x + 15, rect.yMax + 2); } } } // //Another idea // if (style == 1){ // if (sourcePos.x <= thisPos.x){ // if (sourcePos.y >= thisPos.y){ // return new Vector2(rect.xMin - 3, rect.yMax - 10); // } else { // return new Vector2(rect.xMin - 3, rect.yMin + 10); // } // } // if (sourcePos.x > thisPos.x){ // if (sourcePos.y >= thisPos.y){ // return new Vector2(rect.center.x, rect.yMax + 2); // } else { // return new Vector2(rect.center.x, rect.yMin - (this == graph.primeNode? 20 : 0 )); // } // } // } // //YET Another idea // if (style >= 2){ // if (sourcePos.x <= thisPos.x){ // if (sourcePos.y >= thisPos.y){ // return new Vector2(rect.xMin - 3, rect.yMax - 10); // } else { // return new Vector2(rect.xMin - 3, rect.yMin + 10); // } // } // if (sourcePos.x > thisPos.x){ // if (sourcePos.y >= thisPos.y){ // return new Vector2(rect.xMax + 3, rect.yMax - 10); // } else { // return new Vector2(rect.xMax + 3, rect.yMin + 10); // } // } // } return thisPos; } #endif } }