private void DrawMap()
        {
            Vector2 offset = this.offset + new Vector2(mapRect.width / 2, mapRect.height / 2);

            DrawGrid(20.0f * zoomLevel, 0.2f, Color.gray, offset);

            GUIStyle boxStyle        = skin.GetStyle("boxStyle");
            GUIStyle connectionStyle = skin.GetStyle("connectionStyle");
            GUIStyle boolStyle       = skin.GetStyle("boolStyle");

            boxStyle.fontSize = boolStyle.fontSize = (int)(BOX_STYLE_FONT_SIZE * zoomLevel);
            for (int i = 0; i < allNodes.Length; i++)
            {
                // Get and set the position of the node
                Rect toDraw = allNodes[i].boundsInEditor;
                toDraw.position *= zoomLevel;
                toDraw.width    *= zoomLevel;
                toDraw.height   *= zoomLevel;
                toDraw.position += offset;

                // Draw the node on screen and color it accourding to the status it in
                Color oldColor = GUI.color;
                if (inPlayMode) // if in playmode color by current status
                {
                    GUI.color = colorForStatus[allNodes[i].CurrentStatus];
                }
                else if (allNodes[i] == selectedObject)
                {
                    GUI.color = currentSelectedColor;
                }
                else if (allNodes[i].BreakPointEnabled)// if in editor mode color by breakpoint
                {
                    GUI.color = breakPointEnabledColor;
                }
                else
                {
                    GUI.color = breakPointDisabledColor;
                }


                GUIContent content = new GUIContent(allNodes[i].StringInEditor + "\n" + allNodes[i].name, allNodes[i].StringToolTip);
                GUI.Box(toDraw, content, allNodes[i].GetType().IsSubclassOf(typeof(BoolNode)) ? boolStyle : boxStyle);
                GUI.color = oldColor;

                // Get the connection boxes (parent/child connection sockets)
                GetConnectionBoxes(allNodes[i], out Rect upper, out Rect lower);

                // Set positions of the 2 connection boxes
                upper.width   *= zoomLevel;
                upper.height  *= zoomLevel;
                upper.position = (upper.position * zoomLevel) + offset;

                lower.width   *= zoomLevel;
                lower.height  *= zoomLevel;
                lower.position = (lower.position * zoomLevel) + offset;

                // Draw connection boxes
                if (rootNode != allNodes[i])
                {
                    GUI.Box(upper, "", connectionStyle);
                }
                if (allNodes[i].MaxNumberOfChildren != 0)
                {
                    GUI.Box(lower, "", connectionStyle);
                }
            }

            // Draw the connections of each nodes with bezier curves
            for (int i = 0; i < allNodes.Length; i++)
            {
                BNode[] children = allNodes[i].Children;

                if (children == null)
                {
                    continue;
                }

                for (int j = 0; j < children.Length; j++)
                {
                    Vector2 from = (GetUpperMiddle(children[j]) * zoomLevel) + offset;
                    Vector2 to   = (GetLowerMiddle(allNodes[i]) * zoomLevel) + offset;

                    Handles.DrawBezier(from, to, from + Vector2.down * 50f * zoomLevel, to - Vector2.down * 50f * zoomLevel, Color.black, null, 2f);
                }
            }


            // If the user is currently dragging a node, draw from the connecting node to the mouse cursor.
            if (currentDrag == DragType.NodeConnection)
            {
                BNode   node = connectionConstructor.origin;
                Vector2 from = (GetUpperMiddle(node) * zoomLevel) + offset;
                Vector2 to   = (connectionConstructor.mousePos * zoomLevel) + offset;
                Handles.DrawBezier(from, to, from + Vector2.down * 50f * zoomLevel, to - Vector2.down * 50f * zoomLevel, Color.black, null, 2f);
            }
        }
Example #2
0
        private void ProcessEvents(Event e)
        {
            if (!mapRect.Contains(e.mousePosition)) // if mouse not inside the middle map area
            {
                return;
            }

            bool    used     = true;
            Vector2 mousePos = (e.mousePosition - offset - mapRect.position
                                - new Vector2(mapRect.width / 2, mapRect.height / 2)) / zoomLevel;

            switch (e.type)
            {
            case EventType.MouseDown:
                if (e.button == 0)     // left click
                {
                    dragged = false;

                    currentDrag = DragType.Position;

                    if (!GetNodeFromPosition(mousePos, out BNode node))     // is mouse hovering over box
                    {
                        break;
                    }

                    // check if the click was on one of the connection boxes
                    if (inPlayMode == false && GetConnection(mousePos, node, out bool isTop) && isTop)
                    {
                        if (node == rootNode)
                        {
                            Debug.LogWarning("Root node cannot have parents! Change the root node first before adding new parents to this node!");
                            break;
                        }

                        currentDrag = DragType.NodeConnection;

                        RemoveConnection(node);

                        Vector3 connectionMiddlePos = isTop ? GetUpperMiddle(node) : GetLowerMiddle(node);

                        connectionConstructor = new ConnectionConstructor(node, connectionMiddlePos, isTop);
                    }
                    else     // click was not on the connection boxes
                    {
                        currentDrag = DragType.Node;
                        clickedNode = node;
                    }
                }
                break;

            case EventType.MouseDrag:
                if (e.button == 0)     // left click
                {
                    switch (currentDrag)
                    {
                    case DragType.None:
                        goto MouseDragFinished;         // skip the changed set to true flag

                    case DragType.Node:
                        if (inPlayMode == true)
                        {
                            break;
                        }

                        Vector2 toAdd = e.delta;

                        Rect toChange = clickedNode.boundsInEditor;
                        toChange.position         += toAdd / zoomLevel;
                        clickedNode.boundsInEditor = toChange;
                        break;

                    case DragType.Position:
                        offset += e.delta;
                        break;

                    case DragType.NodeConnection:
                        Vector2 nodeOffset = offset + new Vector2(mapRect.width / 2, mapRect.height / 2);

                        BNode   node = connectionConstructor.Value.origin;
                        Vector2 from = (GetUpperMiddle(node)) + nodeOffset;
                        Vector2 to   = from - new Vector2(100, 100);

                        Handles.DrawBezier(from, to, from + Vector2.down * 50f, to - Vector2.down * 50f, Color.black, null, 2f);
                        break;
                    }
                    GUI.changed = true;
                    dragged     = true;

                    MouseDragFinished :;
                }
                break;

            case EventType.MouseUp:
                if (e.button == 0)     // left click
                {
                    if (dragged == false)
                    {
                        if (clickedNode != null)
                        {
                            selectedObject = clickedNode;
                        }
                    }
                    else                                  // if dragged == true
                    {
                        if (currentDrag == DragType.Node) // Save the position of the dragged node
                        {
                            Rect toChange = clickedNode.boundsInEditor;
                            ShapesUtil.RectRoundToNextInt(ref toChange);
                            clickedNode.boundsInEditor = toChange;

                            // The node was moved so the order of the parented children might be wrong
                            if (GetParentNode(clickedNode, out BNode parent))
                            {
                                SortChildren(parent);
                            }

                            AssetDatabase.SaveAssets();
                        }
                        else if (currentDrag == DragType.NodeConnection)             // try to connect the node to its new parent
                        {
                            if (GetNodeFromPosition(mousePos, out BNode newParent))  // if mouse is over hovering over a node
                            {
                                if (newParent == connectionConstructor.Value.origin) // if newParent is self
                                {
                                    goto NodeConnectionFailed;
                                }

                                // if parent already has the maximum number of children
                                if (newParent.MaxNumberOfChildren != -1 &&
                                    newParent.Children.Length >= newParent.MaxNumberOfChildren)
                                {
                                    Debug.LogWarning("Node has already the max number of children!");
                                    goto NodeConnectionFailed;
                                }

                                BNode child = connectionConstructor.Value.origin;
                                if (NodeIsChild(child, newParent))     // If the node is in any way already connected (no loops)
                                {
                                    Debug.LogWarning("Node could not be connected. Connecting these nodes would result in a loop!");
                                    goto NodeConnectionFailed;
                                }

                                // Check if the child node type is allowed on the parent
                                Type[] allowedTypes = newParent.AllowedChildrenTypes;
                                if (allowedTypes != null && allowedTypes.Length != 0)
                                {
                                    bool isAllowed = false;
                                    for (int i = 0; i < allowedTypes.Length; i++)
                                    {
                                        if (child.GetType() == allowedTypes[i] || child.GetType().IsSubclassOf(allowedTypes[i]))
                                        {
                                            isAllowed = true;
                                            break;
                                        }
                                    }
                                    if (isAllowed == false)
                                    {
                                        Debug.LogWarning("The type " + child.GetType() + " is not allowed to be a child of this node.");
                                        goto NodeConnectionFailed;
                                    }
                                }

                                // Everything is fine, add the connection and sort the parents children
                                AddToArray(newParent, child, true);
                                SortChildren(newParent);

                                NodeConnectionFailed :;
                            }
                        } // end if currentDrag is NodeConnection
                    }     // end if dragged
                    dragged               = false;
                    currentDrag           = DragType.None;
                    clickedNode           = null;
                    connectionConstructor = null;
                }
                else if (e.button == 1)     // right click
                {
                    if (inPlayMode == true)
                    {
                        break;
                    }

                    if (!dragged)
                    {
                        if (GetNodeFromPosition(mousePos, out BNode deleteNode))     // is mouse hovering over node
                        {
                            // Show delete menu for node
                            GenericMenu nodeMenu = new GenericMenu();
                            nodeMenu.AddItem(new GUIContent("Delete"), false, () => RemoveNode(deleteNode));
                            nodeMenu.ShowAsContext();
                        }
                        else     // mouse was not over node
                        {
                            // show menu for creating a new node
                            GenericMenu nodeMenu = new GenericMenu();
                            for (int i = 0; i < nodeTypes.Length; i++)
                            {
                                Type   type     = nodeTypes[i];
                                string nodeName = nodeTypes[i].Name;
                                if (nodeName.EndsWith("node", StringComparison.OrdinalIgnoreCase))
                                {
                                    nodeName = nodeName.Substring(0, nodeName.Length - 4);
                                }

                                nodeMenu.AddItem(new GUIContent(nodeName), false, () =>
                                {
                                    BNode createNode          = (BNode)CreateInstance(type);
                                    createNode.name           = "New " + createNode.GetType().Name;
                                    createNode.boundsInEditor = new Rect(mousePos, new Vector2(80, 80));
                                    AssetDatabase.AddObjectToAsset(createNode, tree.targetObject);
                                    AssetDatabase.SaveAssets();
                                });
                            }
                            nodeMenu.ShowAsContext();
                        }
                    }
                }
                break;

            case EventType.ScrollWheel:
                zoomLevel   = Mathf.Clamp(zoomLevel - e.delta.y / 50, MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL);
                GUI.changed = true;
                break;

            default:
                used = false;
                break;
            }
            if (used) // consume event if used
            {
                e.Use();
            }
        }
Example #3
0
 public ConnectionConstructor(BNode origin, Vector2 position, bool isTop)
 {
     this.origin   = origin;
     this.position = position;
     this.isTop    = isTop;
 }
        private void ProcessEvents(Event e)
        {
            if (!mapRect.Contains(e.mousePosition)) // if mouse not inside the middle map area
            {
                return;
            }

            bool    used     = true;
            Vector2 mousePos = (e.mousePosition - offset - mapRect.position - new Vector2(mapRect.width / 2, mapRect.height / 2)) / zoomLevel;

            switch (e.type)
            {
            case EventType.MouseDown:
                if (e.button == 0)     // left click
                {
                    dragged = false;

                    currentDrag = DragType.Position;

                    if (!GetNodeFromPosition(mousePos, out BNode node))     // is mouse hovering over box
                    {
                        break;
                    }

                    // check if the click was on one of the connection boxes and the node was not the root node
                    if (inPlayMode == false && GetConnection(mousePos, node, out bool isTop) && isTop && node != rootNode)
                    {
                        currentDrag = DragType.NodeConnection;

                        RemoveConnection(node);

                        Vector3 connectionMiddlePos = isTop ? GetUpperMiddle(node) : GetLowerMiddle(node);

                        connectionConstructor = new ConnectionConstructor(node, connectionMiddlePos, isTop, mousePos);
                    }
                    else     // click was not on the connection boxes
                    {
                        currentDrag = DragType.Node;
                        nodeMover   = new NodeMover(node, node.boundsInEditor.position - mousePos);
                    }
                }
                break;

            case EventType.MouseDrag:
                if (e.button == 0)     // left click
                {
                    switch (currentDrag)
                    {
                    case DragType.None:
                        goto MouseDragFinished;         // skip the changed set to true flag

                    case DragType.Node:
                        if (inPlayMode == true)
                        {
                            break;
                        }

                        Rect    toChange = nodeMover.node.boundsInEditor;
                        Vector2 newPos   = mousePos + nodeMover.clickedPosition;
                        newPos           /= SNAPPING_PIXELS;
                        newPos.x          = Mathf.Round(newPos.x);
                        newPos.y          = Mathf.Round(newPos.y);
                        toChange.position = newPos * SNAPPING_PIXELS;

                        nodeMover.node.boundsInEditor = toChange;
                        break;

                    case DragType.Position:
                        offset += e.delta;
                        break;

                    case DragType.NodeConnection:
                        connectionConstructor.mousePos = mousePos;
                        break;
                    }
                    GUI.changed = true;

MouseDragFinished:
                    dragged = true;
                }
                break;

            case EventType.MouseUp:
                if (e.button == 0)     // left click
                {
                    if (dragged == false)
                    {
                        selectedObject = null;
                        if (nodeMover != null)
                        {
                            selectedObject = nodeMover.node;
                        }
                    }
                    else                                  // if dragged == true
                    {
                        if (currentDrag == DragType.Node) // Save the position of the dragged node
                        {
                            Rect toChange = nodeMover.node.boundsInEditor;
                            ShapesUtil.RectRoundToNextInt(ref toChange);
                            nodeMover.node.boundsInEditor = toChange;

                            // The node was moved so the order of the parented children might be wrong
                            if (GetParentNode(nodeMover.node, out BNode parent))
                            {
                                SortChildren(parent);
                            }

                            AssetDatabase.SaveAssets();
                        }
                        else if (currentDrag == DragType.NodeConnection)     // try to connect the node to its new parent
                        {
                            TryConnectNodeFromPosition(mousePos);
                        } // end if currentDrag is NodeConnection
                    }     // end if dragged
                    dragged               = false;
                    currentDrag           = DragType.None;
                    nodeMover             = null;
                    connectionConstructor = null;
                }
                else if (e.button == 1)     // right click
                {
                    if (inPlayMode == true)
                    {
                        break;
                    }

                    if (!dragged)
                    {
                        if (GetNodeFromPosition(mousePos, out BNode deleteNode))     // is mouse hovering over node
                        {
                            // Show delete menu for node
                            GenericMenu nodeMenu = new GenericMenu();
                            nodeMenu.AddItem(new GUIContent("Delete"), false, () =>
                            {
                                RemoveNode(deleteNode);
                                Reload();
                            });
                            nodeMenu.ShowAsContext();
                        }
                        else     // mouse was not over node
                        {
                            // show menu for creating a new node
                            GenericMenu nodeMenu = new GenericMenu();
                            for (int i = 0; i < nodeTypes.Length; i++)
                            {
                                Type type = nodeTypes[i];

                                int maxNumberOfChilds = allNodesForTypes[i].MaxNumberOfChildren;

                                string nodeName = nodeTypes[i].Name;
                                if (nodeName.EndsWith("node", StringComparison.OrdinalIgnoreCase))
                                {
                                    nodeName = nodeName.Substring(0, nodeName.Length - 4);
                                }

                                string prefix;
                                if (type.IsSubclassOf(typeof(BoolNode)))
                                {
                                    prefix = NODES_INHERIT_FROM_BOOLNODE_STRING;
                                }
                                else if (maxNumberOfChilds == -1 || maxNumberOfChilds > 0)
                                {
                                    prefix = NODES_WITH_CHILDREN_STRING;
                                }
                                else
                                {
                                    prefix = NODES_WITH_NO_CHILDREN_STRING;
                                }

                                nodeMenu.AddItem(new GUIContent(prefix + "/" + nodeName, allNodesForTypes[i].StringToolTip), false, () =>
                                {
                                    BNode createNode          = (BNode)CreateInstance(type);
                                    createNode.name           = createNode.GetType().Name;
                                    createNode.boundsInEditor = new Rect(mousePos, new Vector2(80, 80));
                                    AssetDatabase.AddObjectToAsset(createNode, tree.targetObject);
                                    AssetDatabase.SaveAssets();
                                    Reload();
                                });
                            }
                            nodeMenu.ShowAsContext();
                        }
                    }
                }
                break;

            case EventType.ScrollWheel:
                zoomLevel   = Mathf.Clamp(zoomLevel - e.delta.y / 50, MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL);
                GUI.changed = true;
                break;

            default:
                used = false;
                break;
            }
            if (used) // consume event if used
            {
                e.Use();
            }
        }
 public NodeMover(BNode node, Vector2 clickedPosition)
 {
     this.node            = node;
     this.clickedPosition = clickedPosition;
 }
Example #6
0
        /// <summary>
        /// Draws the left side of the window. This side is for displaying debug window values, what the root node is
        /// and handles the adding, selction and removing of Values.
        /// </summary>
        private void DrawTreeInfo()
        {
            if (debug)
            {
                Vector2 changedOffset = offset / zoomLevel;
                Vector2 newOffset     = EditorGUILayout.Vector2Field("Position:", changedOffset);
                if (changedOffset != newOffset)
                {
                    offset = newOffset * zoomLevel;
                }

                zoomLevel = Mathf.Clamp(EditorGUILayout.FloatField("Zoomlevel", zoomLevel), MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL);
            }

            lockTreeView = EditorGUILayout.Toggle("Lock Window to current Tree", lockTreeView);

            if (inPlayMode == false)
            {
                // Handle root node
                List <BNode>       parentLessNodes = GetParentlessNodes(); // only nodes without parents can become root
                SerializedProperty rootNode        = tree.FindProperty("root");
                BNode previousRoot = rootNode.objectReferenceValue as BNode;

                string[] choices = new string[parentLessNodes.Count + 1];
                choices[0] = "Null"; // If the root node should be set to nothing

                // fill all the choices with names of the nodes
                int index = 0;
                for (int i = 0; i < parentLessNodes.Count; i++)
                {
                    choices[i + 1] = parentLessNodes[i].name;
                    if (parentLessNodes[i] == previousRoot)
                    {
                        index = i + 1;
                    }
                }

                // Update the new root node
                int newIndex = EditorGUILayout.Popup("root", index, choices);
                if (newIndex != index)
                {
                    if (newIndex == 0)
                    {
                        rootNode.objectReferenceValue = null;
                    }
                    else
                    {
                        rootNode.objectReferenceValue = parentLessNodes[newIndex - 1];
                    }
                }
                this.rootNode = newIndex == 0 ? null : parentLessNodes[newIndex - 1];
                // ---Handle root node

                tree.ApplyModifiedProperties();

                // Add the Button for adding a new value
                if (GUILayout.Button("Add Value"))
                {
                    GenericMenu valueMenu = new GenericMenu();
                    for (int i = 0; i < valueTypes.Length; i++)
                    {
                        Type   type = valueTypes[i];
                        string name = valueTypes[i].Name;
                        if (name.EndsWith("value", StringComparison.OrdinalIgnoreCase))
                        {
                            name = name.Substring(0, name.Length - 5);
                        }

                        valueMenu.AddItem(new GUIContent(name), false, () =>
                        {
                            Value newNode = (Value)CreateInstance(type);
                            newNode.name  = "New " + type.Name;
                            AssetDatabase.AddObjectToAsset(newNode, tree.targetObject);
                            selectedObject = newNode;
                            AssetDatabase.SaveAssets();
                        });
                    }
                    valueMenu.ShowAsContext();
                }
            }

            // Display all values in a list
            for (int i = 0; i < allValues.Length; i++)
            {
                if (GUILayout.Button(allValues[i].name))
                {
                    selectedObject = allValues[i];
                }
            }
        }