Beispiel #1
0
        /// <summary>
        /// Adds a new node to the tree, automatically handles undo, dirty flag and save node.
        /// <param name="tree">The tree to add a new node.</param>
        /// <param name="nodeType">The type of the new node.</param>
        /// <returns>The new node.</returns>
        /// </summary>
        public static ActionNode AddNode(InternalBehaviourTree tree, System.Type nodeType)
        {
            // Validate parameters
            if (tree != null && nodeType != null && nodeType.IsSubclassOf(typeof(ActionNode)) && !nodeType.IsAbstract)
            {
                // Register Undo
                #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                Undo.RegisterUndo(tree, "Add New Node");
                #else
                Undo.RecordObject(tree, "Add New Node");
                #endif

                // Create new node
                var newNode = tree.AddNode(nodeType);

                if (newNode != null)
                {
                    // Saves node and sets dirty flag
                    StateUtility.SetDirty(tree);
                    return(newNode);
                }
            }

            return(null);
        }
Beispiel #2
0
        /// <summary>
        /// Shows the node generic menu.
        /// </summary>
        void ShowNodeContextMenu()
        {
            var menu = new GenericMenu();

            menu.AddItem(new GUIContent("Reset"), false, delegate { StateUtility.ResetNode(target); m_SerializedNode = new SerializedNode(target); m_SerializedNode.Update(); });
            menu.AddSeparator(string.Empty);
            menu.AddItem(new GUIContent("Copy"), false, delegate { BehaviourTreeUtility.nodeToPaste = target; });
            menu.AddSeparator(string.Empty);
            if (target != null)
            {
                menu.AddItem(new GUIContent("Find Script"), false, delegate {
                    MonoScript script = BehaviourTreeUtility.GetNodeScript(target.GetType());
                    if (script != null)
                    {
                        EditorGUIUtility.PingObject(script);
                    }
                });
                menu.AddItem(new GUIContent("Edit Script"), false, delegate {
                    MonoScript script = BehaviourTreeUtility.GetNodeScript(target.GetType());
                    if (script != null)
                    {
                        AssetDatabase.OpenAsset(script);
                    }
                });
            }
            else
            {
                menu.AddDisabledItem(new GUIContent("Find Script"));
                menu.AddDisabledItem(new GUIContent("Edit Script"));
            }

            menu.ShowAsContext();
        }
Beispiel #3
0
        /// <summary>
        /// Adds a new node to the parent, automatically handles undo, dirty flag and save node.
        /// <param name="parent">The branch to add the child.</param>
        /// <param name="childType">The type of the new node.</param>
        /// <returns>The new node.</returns>
        /// </summary>
        public static ActionNode AddNode(BranchNode parent, System.Type childType)
        {
            // Validate parameters
            if (parent != null && parent.tree != null && childType != null)
            {
                // Register Undo
                #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                Undo.RegisterUndo(parent.tree, "Add New Node");
                #else
                Undo.RecordObject(parent.tree, "Add New Node");
                #endif

                var newNode = parent.tree.AddNode(childType);

                if (newNode != null)
                {
                    // Adds new node as child of parent
                    parent.Add(newNode);

                    // Call OnValidate on the parent
                    parent.OnValidate();

                    // Saves node and sets dirty flag
                    StateUtility.SetDirty(parent.tree);
                    return(newNode);
                }
            }

            return(null);
        }
Beispiel #4
0
        /// <summary>
        /// Destroys the suplied node and its hierarchy from the tree.
        /// <param name="node">The node to be destroyed.</param>
        /// <returns>True if the node was successfully destroyed; false otherwise.</returns>
        /// </summary>
        public static bool DestroyNode(ActionNode node)
        {
            // Validate parameters
            if (node != null && node.tree != null)
            {
                // Get parent and tree
                var tree   = node.tree;
                var parent = node.branch;

                // Register Undo
                #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                Undo.RegisterUndo(tree, "Delete " + node.name);
                #else
                Undo.RecordObject(tree, "Delete " + node.name);
                #endif

                // Removes node from parent
                if (parent != null)
                {
                    parent.Remove(node);

                    // Call OnValidate on the parent
                    parent.OnValidate();
                }

                // Removes node from tree
                tree.RemoveNode(node, true);

                // Saves tree and marks dirty flag
                StateUtility.SetDirty(tree);

                return(true);
            }
            return(false);
        }
        /// <summary>
        /// Destroys the suplied node and its hierarchy from the tree.
        /// <param name="node">The node to be destroyed.</param>
        /// <returns>True if the node was successfully destroyed; false otherwise.</returns>
        /// </summary>
        public static bool DestroyNode(ActionNode node)
        {
            // Get the tree action state
            var actionState = node != null ? node.owner as InternalActionState : null;

            // Validate parameters
            if (actionState != null)
            {
                // Register Undo
                #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                Undo.RegisterUndo(actionState, "Delete " + node.name);
                #else
                Undo.RecordObject(actionState, "Delete " + node.name);
                #endif

                // Removes node from actionState
                actionState.RemoveNode(node);

                // Saves actionState and marks dirty flag
                StateUtility.SetDirty(actionState);

                return(true);
            }
            return(false);
        }
Beispiel #6
0
        /// <summary>
        /// Inserts a new node to the supplied branch, automatically handles undo, dirty flag and save node.
        /// <param name="branch">The branch to add a new node.</param>
        /// <param name="index">The index of the new node.</param>
        /// <param name="nodeType">The type of the new node.</param>
        /// <returns>The new node.</returns>
        /// </summary>
        public static ActionNode InsertNode(BranchNode branch, int index, System.Type nodeType)
        {
            // Validate parameters
            if (branch != null && branch.tree != null && nodeType != null && index >= 0 && index <= branch.children.Length)
            {
                // Get the tree
                var tree = branch.tree;

                // Register Undo
                #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                Undo.RegisterUndo(tree, "Insert New Node");
                #else
                Undo.RecordObject(tree, "Insert New Node");
                #endif

                // Create new node
                var newNode = tree.AddNode(nodeType);

                if (newNode != null)
                {
                    // Insert new node
                    branch.Insert(index, newNode);

                    // Call OnValidate on the parent
                    branch.OnValidate();

                    // Saves node and sets dirty flag
                    StateUtility.SetDirty(tree);
                    return(newNode);
                }
            }
            return(null);
        }
        /// <summary>
        /// Shows a context menu callback to add a new state.
        /// </summary>
        void OnAddContextMenu()
        {
            var menu = new GenericMenu();

            var stateScripts = FileUtility.GetScripts <InternalStateBehaviour>();

            for (int i = 0; i < stateScripts.Length; i++)
            {
                System.Type childStateType = stateScripts[i].GetClass();

                // Get the component path
                string           componentPath;
                AddComponentMenu componentMenu = AttributeUtility.GetAttribute <AddComponentMenu>(childStateType, true);
                if (componentMenu != null && componentMenu.componentMenu != string.Empty)
                {
                    componentPath = componentMenu.componentMenu;
                }
                else
                {
                    componentPath = childStateType.ToString().Replace('.', '/');
                }

                menu.AddItem(new GUIContent(componentPath), false, delegate() { StateUtility.AddState(m_Parent, childStateType); });
            }

            // Shows the context menu
            menu.ShowAsContext();
        }
        /// <summary>
        /// Shows a context menu to add a new parent.
        /// </summary>
        void OnContextMenu()
        {
            var menu = new UnityEditor.GenericMenu();
            // Get the active game object
            var gameObject = Selection.activeGameObject;

            // The selected game object is not null?
            if (gameObject != null)
            {
                // Gets all scripts that inherits from ParentBehaviour class
                MonoScript[] scripts = FileUtility.GetScripts <ParentBehaviour>();
                for (int i = 0; i < scripts.Length; i++)
                {
                    var type = scripts[i].GetClass();

                    // Get the component path
                    string           componentPath = "Add Parent/";
                    AddComponentMenu componentMenu = AttributeUtility.GetAttribute <AddComponentMenu>(type, false);
                    if (componentMenu == null || componentMenu.componentMenu != string.Empty)
                    {
                        componentMenu = AttributeUtility.GetAttribute <AddComponentMenu>(type, true);
                        if (componentMenu != null && componentMenu.componentMenu != string.Empty)
                        {
                            componentPath += componentMenu.componentMenu;
                        }
                        else
                        {
                            componentPath += type.ToString().Replace('.', '/');
                        }

                        // Add to menu
                        menu.AddItem(new GUIContent(componentPath), false, delegate() { BehaviourWindow.activeParent = StateUtility.AddState(gameObject, type) as ParentBehaviour; });
                    }
                }
            }
            else
            {
                menu.AddDisabledItem(new GUIContent("Add Parent/"));
                ShowNotification(new GUIContent("Select a Game Object and right click in this window!"));
            }

            // Add option to paste states
            if (Selection.activeGameObject != null && StateUtility.statesToPaste != null && StateUtility.statesToPaste.Length > 0)
            {
                menu.AddItem(new GUIContent("Paste State"), false, delegate() { StateUtility.CloneStates(Selection.activeGameObject, StateUtility.statesToPaste, null); });
            }
            else
            {
                menu.AddDisabledItem(new GUIContent("Paste State"));
            }

            // Refresh window?
            // menu.AddSeparator("");
            // menu.AddItem(new GUIContent("Refresh"), false ,Refresh);

            // Shows the controller menu
            menu.ShowAsContext();
        }
        /// <summary>
        /// Adds a state to the supplied parent.
        /// Automatically handles undo.
        /// <param name="parent">The ParentBehaviour to add the new state.</param>
        /// <param name="type">The new state type.</param>
        /// <returns>The new created state.<returns>
        /// </summary>
        public static InternalStateBehaviour AddState(ParentBehaviour parent, System.Type type)
        {
            // Validate parameters
            if (type != null && parent != null)
            {
                // Create and register undo
                #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                Undo.RegisterSceneUndo("Create State (" + type.Name + ")");
                #endif

                InternalStateBehaviour newState = parent.AddState(type);


                if (newState != null)
                {
                    // Register undo
                    #if !UNITY_4_0_0 && !UNITY_4_1 && !UNITY_4_2
                    Undo.RegisterCreatedObjectUndo(newState, "Create State (" + type.Name + ")");
                    #endif

                    // The parent is a FSM?
                    var fsm = parent as InternalStateMachine;
                    if (fsm != null)
                    {
                        // The newState is an AnyState?
                        if (newState is InternalAnyState)
                        {
                            // The fsm already has an AnyState?
                            if (fsm.anyState != null)
                            {
                                // Destroy the curren anyState
                                StateUtility.Destroy(fsm.anyState);
                            }

                            // Add the new anyState
                            fsm.anyState = newState as InternalAnyState;
                        }
                        // The start state is null?
                        else if (fsm.startState == null)
                        {
                            // Set the new state as the start state
                            fsm.startState = newState;
                            EditorUtility.SetDirty(fsm);
                        }
                    }

                    // Sets dirty flag
                    EditorUtility.SetDirty(parent.gameObject);
                }

                return(newState);
            }
            return(null);
        }
Beispiel #10
0
        /// <summary>
        /// Remove the suplied branch from the tree.
        /// <param name="branch">The node to be removed.</param>
        /// <returns>True if the node was successfully removed; false otherwise.</returns>
        /// </summary>
        public static bool RemoveBranch(BranchNode branch)
        {
            // The Branch is not a decorator
            if (branch != null && branch.tree != null)
            {
                // Gets parent's children and node's id
                var          parent   = branch.branch;
                ActionNode[] children = branch.children;
                var          tree     = branch.tree;

                // The parent is a decorator or null (node is root) and the branch has more than one child?
                if (children.Length >= 2 && (parent == null || parent is DecoratorNode) || parent == null)
                {
                    EditorApplication.Beep();
                    return(false);
                }

                // Register Undo
                #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                Undo.RegisterUndo(branch.tree, "Remove Branch");
                #else
                Undo.RecordObject(branch.tree, "Remove Branch");
                #endif

                // Removes children from branch and adds to parent
                if (parent != null)
                {
                    // Get the branch index
                    int branchIndex = (new List <ActionNode>(parent.children)).IndexOf(branch);
                    parent.Remove(branch);

                    for (int i = 0; i < children.Length; i++)
                    {
                        branch.Remove(children[i]);
                        parent.Insert(branchIndex++, children[i]);
                    }

                    // Call OnValidate on the parent
                    parent.OnValidate();
                }

                // Removes node from tree
                tree.RemoveNode(branch, false);

                // Saves tree and marks dirty flag
                StateUtility.SetDirty(tree);

                return(true);
            }
            return(false);
        }
Beispiel #11
0
        /// <summary>
        /// Callback called whenever the supplied list changes its order.
        /// <param name="list">The target list.</param>
        /// </summary>
        private void OnReorderNode(ReorderableList list)
        {
            // Register Undo
            #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
            Undo.RegisterUndo(m_ActionState, "Move Node");
            #else
            Undo.RecordObject(m_ActionState, "Move Node");
            #endif

            // Set dirty flag
            StateUtility.SetDirty(m_ActionState);

            m_ActionState.HierarchyChanged();

            RegisterEditorOnGUI();
        }
Beispiel #12
0
        /// <summary>
        /// Apply property modifications.
        /// </summary>
        public void ApplyModifiedProperties()
        {
            if (m_Target != null && m_PropertiesChanged.Count > 0)
            {
                var ownerUnityObj    = m_Target.owner as UnityEngine.Object;
                var variableModified = new List <Variable>();

                // Register undo
                #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                Undo.RegisterUndo(ownerUnityObj, "Inspector");
                #else
                Undo.RecordObject(ownerUnityObj, "Inspector");
                #endif

                // Call ApplyModifiedValue in all change properties
                for (int i = 0; i < m_PropertiesChanged.Count; i++)
                {
                    // Apply changes in the property data
                    m_PropertiesChanged[i].ApplyModifiedValue();

                    // Recreate data?
                    m_RecreateData = m_RecreateData || m_PropertiesChanged[i].hasChildren || m_PropertiesChanged[i].propertyType == NodePropertyType.Variable;

                    // It is a variable?
                    var variable = m_PropertiesChanged[i].target as Variable;
                    if (variable != null && !variableModified.Contains(variable))
                    {
                        variableModified.Add(variable);
                    }
                }

                // Clear changed properties
                m_PropertiesChanged.Clear();

                // Call OnValidate
                foreach (var variable in variableModified)
                {
                    variable.OnValidate();
                }
                m_Target.OnValidate();

                // Set tree dirty flag
                StateUtility.SetDirty(m_Target.owner);
            }
        }
        /// <summary>
        /// Reset the supplied node properties.
        /// <param name="node">The node to be reseted.</param>
        /// </summary>
        public static void ResetNode(ActionNode node)
        {
            // Get the owner as an Uniyt object
            var ownerUnityObj = node != null ? node.owner as UnityEngine.Object : null;

            // Validate parameters
            if (ownerUnityObj != null)
            {
                // Register Undo
                #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                Undo.RegisterUndo(ownerUnityObj, "Reset Node");
                #else
                Undo.RecordObject(ownerUnityObj, "Reset Node");
                #endif

                node.name = node.GetType().Name;
                node.Reset();
                node.OnValidate();
                StateUtility.SetDirty(node.owner);
            }
        }
Beispiel #14
0
        /// <summary>
        /// Shows a context menu for the supplied transition.
        /// <param name="transition">The target transition.</param>
        /// </summary>
        void ShowContextMenu(StateTransition transition)
        {
            var menu           = new UnityEditor.GenericMenu();
            var currentEventID = transition.eventID;

            // Add none
            menu.AddItem(new GUIContent("None"), currentEventID == 0, delegate() { StateUtility.SetNewEvent(m_State, transition, 0); this.Refresh(); });

            // Add blackboard events
            var blackboard = m_State.blackboard;

            if (blackboard != null)
            {
                foreach (var fsmEvent in blackboard.fsmEvents)
                {
                    int eventId = fsmEvent.id;
                    menu.AddItem(new GUIContent(fsmEvent.name), currentEventID == fsmEvent.id, delegate() { StateUtility.SetNewEvent(m_State, transition, eventId); this.Refresh(); });
                }
            }

            // Add GlobalBlackboard events
            // This is not The GlobalBlackboard?
            if (InternalGlobalBlackboard.Instance != null && blackboard != InternalGlobalBlackboard.Instance)
            {
                foreach (var globalEvent in InternalGlobalBlackboard.Instance.fsmEvents)
                {
                    int eventId   = globalEvent.id;
                    var eventName = globalEvent.isSystem ? "System/" + globalEvent.name : "Global/" + globalEvent.name;
                    menu.AddItem(new GUIContent(eventName), currentEventID == globalEvent.id, delegate() { StateUtility.SetNewEvent(m_State, transition, eventId); this.Refresh(); });
                }
            }

            menu.AddSeparator("");  // Separator

            menu.AddItem(new GUIContent("Delete"), false, delegate() { StateUtility.RemoveTransition(m_State, transition); this.Refresh(); });

            // Shows the context menu
            menu.ShowAsContext();
        }
Beispiel #15
0
        /// <summary>
        /// Paste the node in BehaviourTreeUtility.nodeToPaste in the supplied tree.
        /// <param name="tree">The target tree.</param>
        /// <param name="parent">Optional parent to paste the node; or null to paste as a root node.</param>
        /// <returns>The pasted node.</returns>
        /// </summary>
        public static ActionNode PasteNode(InternalBehaviourTree tree, BranchNode parent = null)
        {
            // Get the node to be pasted
            var node = BehaviourTreeUtility.nodeToPaste;

            // Validate parameters
            if (node != null && tree != null)
            {
                // Register Undo
                #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                Undo.RegisterUndo(tree, "Paste Node");
                #else
                Undo.RecordObject(tree, "Paste Node");
                #endif

                var newNode = node.Copy(tree);

                if (newNode != null)
                {
                    // Add to parent branch?
                    if (parent != null)
                    {
                        parent.Add(newNode);

                        // Call OnValidate on the parent
                        parent.OnValidate();
                    }

                    // Saves node and sets dirty flag
                    StateUtility.SetDirty(tree);

                    // Reload tree to update variables
                    tree.LoadNodes();
                }
                return(newNode);
            }
            return(null);
        }
        /// <summary>
        /// Paste the supplied nodes in the supplied ActionState.
        /// <param name="actionState">The ActionState to paste the node.</param>
        /// <param name="nodes">The nodes to be pasted.</param>
        /// <returns>The pasted nodes.</returns>
        /// </summary>
        public static ActionNode[] PasteNodes(InternalActionState actionState, ActionNode[] nodes)
        {
            var newNodes = new List <ActionNode>();

            // Validate parameters
            if (nodes != null && actionState != null)
            {
                // Register Undo
                #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                Undo.RegisterUndo(actionState, "Paste Node");
                #else
                Undo.RecordObject(actionState, "Paste Node");
                #endif

                // Copy nodes
                for (int i = 0; i < nodes.Length; i++)
                {
                    if (nodes[i] != null && !(nodes[i] is BranchNode))
                    {
                        ActionNode newNode = nodes[i].Copy(actionState);
                        if (newNode != null)
                        {
                            newNodes.Add(newNode);
                        }
                    }
                }

                if (newNodes.Count > 0)
                {
                    // Saves node and sets dirty flag
                    StateUtility.SetDirty(actionState);

                    // Reload actionState to update variables
                    actionState.LoadNodes();
                }
            }
            return(newNodes.ToArray());
        }
Beispiel #17
0
        /// <summary>
        /// Inserts a new node to the supplied branch, automatically handles undo, dirty flag and save node.
        /// <param name="node">The branch to add a new node.</param>
        /// <param name="newNodePosition">Move the node to the position of this node.</param>
        /// <param name="branch">The branch to drop the node or null.</param>
        /// </summary>
        public static bool MoveNode(ActionNode node, ActionNode newNodePosition, BranchNode branch)
        {
            // Validate parameters
            if (node != null && node.tree != null)
            {
                // Get the tree
                var tree = node.tree;

                // The node does not belongs to the tree?
                if (!tree.GetNodes().Contains(node))
                {
                    return(false);
                }

                // Register Undo
                #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                Undo.RegisterUndo(tree, "Move Node");
                #else
                Undo.RecordObject(tree, "Move Node");
                #endif

                // The node will be a root node?
                if (branch == null)
                {
                    // Remove from old branch
                    if (node.branch != null)
                    {
                        BranchNode oldBranch = node.branch;
                        node.branch.Remove(node);

                        // Call OnValidate on old branch
                        oldBranch.OnValidate();
                    }

                    if (newNodePosition == null)
                    {
                        var newIndex = node.tree.GetNodes().Count - 1;
                        node.tree.MoveNode(node.GetIndex(), newIndex);
                    }
                    else
                    {
                        var newIndex = newNodePosition.root.GetIndex();
                        node.tree.MoveNode(node.GetIndex(), newIndex);
                    }
                }
                // The new node position is null?
                else if (newNodePosition == null)
                {
                    // node.branch = branch;
                    // Store old branch
                    var oldBranch = node.branch;

                    // Remove from old branch
                    if (oldBranch != null)
                    {
                        oldBranch.Remove(node);
                    }

                    // Add to drop
                    if (!branch.Add(node))
                    {
                        // Restore old branch
                        if (oldBranch != null)
                        {
                            oldBranch.Add(node);
                        }
                        return(false);
                    }

                    // Call OnValidate on branches
                    branch.OnValidate();
                    if (oldBranch != null && oldBranch != branch)
                    {
                        oldBranch.OnValidate();
                    }

                    node.tree.HierarchyChanged();
                }
                else
                {
                    // Cache the oldBranch
                    BranchNode oldBranch = node.branch;

                    // Get index
                    var index    = -1;
                    var children = branch.children;
                    for (int i = 0; i < children.Length; i++)
                    {
                        if (children[i] == newNodePosition)
                        {
                            index = i;
                            break;
                        }
                    }

                    // The index is invalid?
                    if (index < 0 || !branch.Insert(index, node))
                    {
                        return(false);
                    }
                    else
                    {
                        // Call OnValidate on the branches
                        if (oldBranch != null)
                        {
                            oldBranch.OnValidate();
                        }
                        branch.OnValidate();
                        node.tree.HierarchyChanged();
                    }
                }

                // Save move opration
                StateUtility.SetDirty(tree);

                return(true);
            }
            return(false);
        }
Beispiel #18
0
        /// <summary>
        /// Shows the context menu.
        /// </summary>
        void OnContextMenu()
        {
            var menu      = new GenericMenu();
            var activeFsm = BehaviourWindow.activeFsm;

            if (activeFsm != null)
            {
                m_LastMousePos = Event.current.mousePosition;
                // Get the states scripts
                MonoScript[] stateScripts = FileUtility.GetScripts <InternalStateBehaviour>();
                for (int i = 0; i < stateScripts.Length; i++)
                {
                    System.Type type = stateScripts[i].GetClass();

                    // Get the component path
                    string           componentPath = "Add State/";
                    AddComponentMenu componentMenu = AttributeUtility.GetAttribute <AddComponentMenu>(type, false);
                    if (componentMenu == null || componentMenu.componentMenu != string.Empty)
                    {
                        componentMenu = AttributeUtility.GetAttribute <AddComponentMenu>(type, true);
                        if (componentMenu != null && componentMenu.componentMenu != string.Empty)
                        {
                            componentPath += componentMenu.componentMenu;
                        }
                        else
                        {
                            componentPath += type.ToString().Replace('.', '/');
                        }

                        menu.AddItem(new GUIContent(componentPath), false, delegate() {
                            InternalStateBehaviour newState = StateUtility.AddState(activeFsm, type);
                            // Sets the newState position and dirty flag
                            if (newState != null)
                            {
                                newState.position = m_LastMousePos - new Vector2(StateGUI.defaultWidth, StateGUI.defaultHeight) * .5f;
                                EditorUtility.SetDirty(newState);
                            }
                        });
                    }
                }
            }
            else
            {
                menu.AddDisabledItem(new GUIContent("Add State"));
            }

            // Separator
            menu.AddSeparator("");

            menu.AddItem(new GUIContent("Copy FSM"), false, delegate() { StateUtility.statesToPaste = new InternalStateBehaviour[] { activeFsm }; });

            if (StateUtility.statesToPaste != null && StateUtility.statesToPaste.Length > 0 && activeFsm != null)
            {
                menu.AddItem(new GUIContent("Paste State"), false, delegate() { StateUtility.PasteStates(activeFsm); });
            }
            else
            {
                menu.AddDisabledItem(new GUIContent("Paste State"));
            }

            // Separator
            menu.AddSeparator("");

            menu.AddItem(new GUIContent("Delete FSM"), false, delegate() { StateUtility.Destroy(activeFsm); });

            // menu.AddSeparator("");  // Separator

            // if (BehaviourWindow.Instance != null)
            //     menu.AddItem(new GUIContent("Refresh"), false, BehaviourWindow.Instance.Refresh);
            // else
            //     menu.AddDisabledItem(new GUIContent("Refresh"));

            // Shows the context menu
            menu.ShowAsContext();
        }
        /// <summary>
        /// Destroys the supplied state.
        /// Automatically handles undo.
        /// <param name="state">The state to be destroyed.</param>
        /// </summary>
        public static void Destroy(InternalStateBehaviour state)
        {
            // its a valid state
            if (state != null)
            {
                var gameObject = state.gameObject;                  // stores the gameObject to set dirty flag
                var isPrefab   = FileUtility.IsPrefab(gameObject);
                var monoState  = state as InternalMonoState;        // its a mono state?

                // It is a fsm?
                if (state is ParentBehaviour)
                {
                    var parent = state as ParentBehaviour;
                    foreach (var child in parent.states)
                    {
                        StateUtility.Destroy(child);
                    }
                }

                if (Application.isPlaying && !isPrefab)
                {
                    // Its a MonoState and the user wants to destroy mono behaviour to?
                    if (monoState != null && monoState.monoBehaviour != null && EditorUtility.DisplayDialog("Destroy MonoBehaviour?", "Do you want to destroy the " + monoState.monoBehaviour.GetType().ToString() + "?", "Ok", "Cancel"))
                    {
                        var monoStateGO = monoState.gameObject;
                        Object.Destroy(monoState.monoBehaviour);
                        EditorUtility.SetDirty(monoStateGO);
                    }
                    Object.Destroy(state);
                }
                else
                {
                    // Register scene undo
                    #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                    Undo.RegisterSceneUndo("Delete");
                    #endif

                    // Its a MonoState and the user wants to destroy the MonoBehaviour to?
                    if (monoState != null && monoState.monoBehaviour != null && EditorUtility.DisplayDialog("Destroy MonoBehaviour?", "Do you want to destroy the " + monoState.monoBehaviour.GetType().ToString() + "?", "Ok", "Cancel"))
                    {
                        // Gets the  MonoState game object
                        var monoStateGO = monoState.gameObject;

                        // Destroy the mono behaviour
                        #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                        Object.DestroyImmediate(monoState.monoBehaviour, true);
                        #else
                        Undo.DestroyObjectImmediate(monoState.monoBehaviour);
                        #endif

                        // Set game object dirty flag
                        EditorUtility.SetDirty(monoStateGO);
                    }

                    // Destroys the state
                    #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                    Object.DestroyImmediate(state, true);
                    #else
                    Undo.DestroyObjectImmediate(state);
                    #endif
                }

                EditorUtility.SetDirty(gameObject);
            }
        }
        /// <summary>
        /// Paste the state in StateUtility.stateToPaste in the supplied fsm.
        /// <param name="gameObject">The target gameObject.</param>
        /// <param name="originalStates">The original states.</param>
        /// <param name="parent">Optionally parent for the cloned states.</param>
        /// </summary>
        public static void CloneStates(GameObject gameObject, InternalStateBehaviour[] originalStates, ParentBehaviour parent)
        {
            if (gameObject != null && originalStates != null && originalStates.Length > 0)
            {
                var orginalClone = new Dictionary <InternalStateBehaviour, InternalStateBehaviour>();
                var originalFsm = parent != null ? originalStates[0].parent as InternalStateMachine : null;
                var newFsm = parent as InternalStateMachine;
                InternalStateBehaviour startState = null, concurrentState = null;
                InternalAnyState       anyState = null;

                // Copy blackboard data?
                var newBlackboard = gameObject.GetComponent <InternalBlackboard>();
                if (newBlackboard == null)
                {
                    // Get the original blackboard
                    InternalBlackboard originalBlackboard = originalStates[0].GetComponent <InternalBlackboard>();

                    #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                    Undo.RegisterSceneUndo("Paste State");
                    // Create the new blacbkoard
                    newBlackboard = gameObject.AddComponent(originalBlackboard.GetType()) as InternalBlackboard;
                    #else
                    // Create the new blacbkoard
                    newBlackboard = gameObject.AddComponent(originalBlackboard.GetType()) as InternalBlackboard;
                    if (newBlackboard != null)
                    {
                        Undo.RegisterCreatedObjectUndo(newBlackboard, "Paste State");
                    }
                    #endif

                    // Copy serialized values
                    EditorUtility.CopySerialized(originalBlackboard, newBlackboard);
                }

                foreach (InternalStateBehaviour state in originalStates)
                {
                    // Don't clone AnyState in StateMachines
                    if (state != null && (newFsm == null || !(state is InternalAnyState) || newFsm.anyState == null))
                    {
                        #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                        Undo.RegisterSceneUndo("Paste State");
                        // Create a new state
                        var newState = gameObject.AddComponent(state.GetType()) as InternalStateBehaviour;
                        #else
                        // Create a new state
                        var newState = gameObject.AddComponent(state.GetType()) as InternalStateBehaviour;
                        if (newState != null)
                        {
                            Undo.RegisterCreatedObjectUndo(newState, "Paste State");
                        }
                        #endif

                        if (newState != null)
                        {
                            // Store state
                            orginalClone.Add(state, newState);

                            // Copy serialized values
                            EditorUtility.CopySerialized(state, newState);

                            // Update blackboard
                            if (state.gameObject != newState.gameObject)
                            {
                                var serialObj = new SerializedObject(newState);
                                serialObj.FindProperty("m_Blackboard").objectReferenceValue = newBlackboard;
                                serialObj.ApplyModifiedProperties();
                                serialObj.Dispose();
                            }

                            // Update the AnyState, StartState and ConcurrentState
                            if (newState is InternalStateMachine)
                            {
                                var fsm = newState as InternalStateMachine;
                                fsm.startState      = null;
                                fsm.concurrentState = null;
                                fsm.anyState        = null;
                            }

                            EditorUtility.SetDirty(newState);

                            // Set new parent
                            if (parent != null)
                            {
                                newState.parent = parent;

                                // Update position
                                if (parent == state.parent)
                                {
                                    newState.position += new Vector2(20f, 20f);
                                }
                            }
                            else
                            {
                                newState.parent = null;
                            }

                            // Saves state and sets dirty flag
                            INodeOwner nodeOwner = newState as INodeOwner;
                            if (nodeOwner != null)
                            {
                                nodeOwner.LoadNodes();
                                StateUtility.SetDirty(nodeOwner);
                            }
                            else
                            {
                                EditorUtility.SetDirty(newState);
                            }

                            // Try to get the StartState, AnyState and ConcurrentState
                            if (originalFsm != null)
                            {
                                if (originalFsm.startState == state)
                                {
                                    startState = newState;
                                }
                                if (anyState == null)
                                {
                                    anyState = newState as InternalAnyState;
                                }
                                if (originalFsm.concurrentState == state)
                                {
                                    concurrentState = newState;
                                }
                            }
                        }
                    }
                }

                // Set StartState, AnyState and ConcurrentState
                if (newFsm != null)
                {
                    if (newFsm.startState == null)
                    {
                        newFsm.startState = startState;
                    }
                    if (newFsm.anyState == null)
                    {
                        newFsm.anyState = anyState;
                    }
                    if (newFsm.concurrentState == null)
                    {
                        newFsm.concurrentState = concurrentState;
                    }
                    EditorUtility.SetDirty(newFsm);
                }

                // Try to update the transitions' destination
                foreach (KeyValuePair <InternalStateBehaviour, InternalStateBehaviour> pair in orginalClone)
                {
                    InternalStateBehaviour state    = pair.Key;
                    InternalStateBehaviour newState = pair.Value;

                    // Update the newState transition
                    for (int i = 0; i < newState.transitions.Length && i < state.transitions.Length; i++)
                    {
                        // The original destination is valid?
                        if (state.transitions[i].destination != null && orginalClone.ContainsKey(state.transitions[i].destination))
                        {
                            newState.transitions[i].destination = orginalClone[state.transitions[i].destination];
                        }
                    }

                    if (newState is ParentBehaviour)
                    {
                        var stateAsParent = state as ParentBehaviour;

                        // Removes the newState from the children state to avoid an infinite loop
                        List <InternalStateBehaviour> children = stateAsParent.states;
                        if (children.Contains(newState))
                        {
                            children.Remove(newState);
                        }

                        StateUtility.CloneStates(newState.gameObject, children.ToArray(), newState as ParentBehaviour);
                    }

                    EditorUtility.SetDirty(newState);
                }

                EditorUtility.SetDirty(gameObject);
            }
        }
Beispiel #21
0
        /// <summary>
        /// Draw the transition arrows.
        /// </summary>
        public override void OnGUIAfterWindows()
        {
            if (m_StatesGUI != null)
            {
                // Trying to create connections?
                if (TransitionDragAndDrop.dragging != null)
                {
                    switch (Event.current.type)
                    {
                    // Mouse Up? Let's try to connect a transition destination...
                    case EventType.MouseUp:
                        // Mouse button left?
                        if (Event.current.button == 0)
                        {
                            var mousePos = Event.current.mousePosition;

                            // The mouse is over a StateGUI?
                            foreach (var guiState in m_StatesGUI)
                            {
                                if (guiState.rect.Contains(mousePos))
                                {
                                    StateUtility.SetNewDestination(TransitionDragAndDrop.state, TransitionDragAndDrop.dragging, guiState.state);
                                    Refresh();
                                    Event.current.Use();
                                    break;
                                }
                            }

                            // Ignores the Transition drag'n & drop operation
                            TransitionDragAndDrop.AcceptDrag();
                            Repaint();
                        }
                        break;

                    // Cancel drag
                    case EventType.Used:
                        goto case EventType.Ignore;

                    case EventType.Ignore:
                        TransitionDragAndDrop.AcceptDrag();
                        Event.current.Use();
                        Repaint();
                        break;

                    // Draws the transition destination when dragging.
                    case EventType.Repaint:
                        // Is dragging?
                        if (TransitionDragAndDrop.isDragging)
                        {
                            // Validate dragging members
                            var guiState = TransitionDragAndDrop.guiState;
                            if (guiState != null && guiState.state != null)
                            {
                                // Gets the mouse position and creates a Rect
                                var mousePos    = Event.current.mousePosition;
                                var destRect    = new Rect(mousePos.x, mousePos.y, 0, 0);
                                var destYOffset = 0f;

                                // The mouse is over a StateGUI?
                                foreach (var _guiState in m_StatesGUI)
                                {
                                    if (_guiState.rect.Contains(mousePos))
                                    {
                                        // Updates the destRect and destYOffset.
                                        destRect    = _guiState.rect;
                                        destYOffset = StateGUI.defaultHeight * .5f;
                                        break;
                                    }
                                }

                                // Draws the bezier line
                                TransitionDragAndDrop.transitionGUI.DrawArrow(guiState.rect, destRect, destYOffset);
                            }
                        }
                        break;

                    case EventType.MouseDrag:
                        if (TransitionDragAndDrop.isDragging)
                        {
                            Repaint();
                        }
                        break;
                    }
                }
            }

            // Get the current event
            Event current   = Event.current;
            var   activeFsm = BehaviourWindow.activeFsm; // cached activeFsm

            switch (current.type)
            {
            // Show context menu?
            case EventType.ContextClick:
                OnContextMenu();
                Event.current.Use();
                break;

            case EventType.MouseDown:
                // If the left mouse button is down then unselect the state and start the dragging rect
                if (current.button == 0)
                {
                    BehaviourWindow.activeState = null;
                    EditorGUIUtility.hotControl = 0;
                    GUIUtility.keyboardControl  = 0;
                    if (!current.alt && !current.shift)
                    {
                        m_SelectionStartPoint = current.mousePosition;
                        m_SelectionRect       = true;
                    }
                    current.Use();
                }
                break;

            // Event ignored?
            case EventType.Ignore:
                // Cancel selection rect?
                if (m_SelectionRect)
                {
                    goto case EventType.MouseUp;
                }
                break;

            // Cancel selection rect?
            case EventType.MouseUp:
                if (m_SelectionRect)
                {
                    m_SelectionRect       = false;
                    GUIUtility.hotControl = 0;
                    SelectNodesInRect(GetRectFromPoints(m_SelectionStartPoint, current.mousePosition));
                    current.Use();
                }
                break;

            // Selection rect?
            case EventType.MouseDrag:
                if (m_SelectionRect)
                {
                    current.Use();
                }
                else if (current.button == 2)
                {
                    m_ScrollView -= current.delta;
                    current.Use();
                }
                break;

            // Delete selected states?
            case EventType.ValidateCommand:
                // Use event to call event ExecuteCommand
                if (current.commandName == "Paste" && activeFsm != null && StateUtility.statesToPaste != null && StateUtility.statesToPaste.Length > 0)
                {
                    current.Use();
                }
                else if (current.commandName == "Copy" && activeFsm != null && Selection.objects.Length > 0)
                {
                    current.Use();
                }
                else if (current.commandName == "Duplicate" && activeFsm != null)
                {
                    // Is there a selected state?
                    foreach (var obj in Selection.objects)
                    {
                        if (obj is InternalStateBehaviour)
                        {
                            current.Use();
                            break;
                        }
                    }
                }
                else if ((current.commandName == "Delete" || current.commandName == "SoftDelete") && BehaviourWindow.activeState != null)
                {
                    current.Use();
                }
                break;

            case EventType.ExecuteCommand:
                if (current.commandName == "Paste")
                {
                    StateUtility.PasteStates(activeFsm);
                }
                else if (current.commandName == "Copy")
                {
                    StateUtility.CopySelectedStates();
                }
                else if (current.commandName == "Duplicate")
                {
                    StateUtility.CopySelectedStates();
                    StateUtility.PasteStates(activeFsm);
                }
                else if (current.commandName == "Delete" || current.commandName == "SoftDelete")
                {
                    foreach (InternalStateBehaviour state in Selection.objects)
                    {
                        StateUtility.Destroy(state);
                    }
                    Refresh();
                    current.Use();
                }
                break;

            // Dragging?
            case EventType.DragUpdated:
                if (DragAndDrop.objectReferences.Length > 0 && DragAndDrop.objectReferences[0] is MonoScript && BehaviourWindow.activeFsm != null)
                {
                    DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
                }
                break;

            // Drag perform?
            case EventType.DragPerform:
                if (DragAndDrop.objectReferences.Length > 0 && DragAndDrop.objectReferences[0] is MonoScript && BehaviourWindow.activeFsm != null)
                {
                    var index         = 0;                          // index of added states
                    var mousePosition = current.mousePosition - new Vector2(StateGUI.defaultWidth, StateGUI.defaultHeight) * .5f;

                    // Register undo
                        #if UNITY_4_0_0 || UNITY_4_1 || UNITY_4_2
                    Undo.RegisterSceneUndo("Add States");
                        #endif

                    // Get all GetScripts
                    var scripts = new List <MonoScript>();
                    foreach (var obj in DragAndDrop.objectReferences)
                    {
                        var script = obj as MonoScript;
                        if (script != null)
                        {
                            scripts.Add(script);
                        }
                    }

                    // Go trough all monoscripts
                    foreach (MonoScript monoScript in scripts)
                    {
                        var type = monoScript.GetClass();
                        // The type is a valid InternalStateBehaviour instance?
                        if (type != null && !type.IsAbstract)
                        {
                            // Add state behaviour
                            if (type.IsSubclassOf(typeof(InternalStateBehaviour)))
                            {
                                var newState = StateUtility.AddState(activeFsm, type);

                                // The state is valid?
                                if (newState != null)
                                {
                                    // Set the newState position
                                    newState.position = mousePosition + new Vector2(StateGUI.defaultWidth * index * .5f, 20f * index);
                                    index++;
                                }
                            }
                            // Add mono state
                            else if (type.IsSubclassOf(typeof(MonoBehaviour)))
                            {
                                var newMonoState = StateUtility.AddState(activeFsm, typeof(InternalMonoState)) as InternalMonoState;

                                // Set the newMonoState position
                                if (newMonoState != null)
                                {
                                    // Set mono state position
                                    newMonoState.position = mousePosition + new Vector2(StateGUI.defaultWidth * index * .5f, 20f * index);
                                    index++;
                                    newMonoState.monoBehaviour = newMonoState.gameObject.AddComponent(type) as MonoBehaviour;

                                    // Register undo
                                        #if !UNITY_4_0_0 && !UNITY_4_1 && !UNITY_4_2
                                    if (newMonoState.monoBehaviour != null)
                                    {
                                        Undo.RegisterCreatedObjectUndo(newMonoState.monoBehaviour, "Add Component");
                                    }
                                        #endif
                                }
                            }
                        }
                    }

                    // Sets dirty flag
                    if (activeFsm.gameObject != null)
                    {
                        EditorUtility.SetDirty(activeFsm.gameObject);
                    }

                    // Accept drag
                    DragAndDrop.AcceptDrag();
                    current.Use();

                    Refresh();
                }
                break;

            // Draw the selection rect?
            case EventType.Repaint:
                if (m_SelectionRect)
                {
                    s_Styles.selectionRect.Draw(GetRectFromPoints(m_SelectionStartPoint, current.mousePosition), false, false, false, false);
                }
                break;
            }

            GUI.EndScrollView();    // Close scroolView.
            GUI.EndGroup();         // Close group
        }
Beispiel #22
0
        /// <summary>
        /// Shows the context menu.
        /// </summary>
        protected virtual void OnContextMenu()
        {
            // Create the menu
            var menu = new UnityEditor.GenericMenu();

            if (m_State != null)
            {
                // Set as start state
                if (m_State.fsm != null && !(m_State is InternalAnyState))
                {
                    menu.AddItem(new GUIContent("Set as Start"), false, delegate() { StateUtility.SetAsStart(m_State); this.Refresh(); });
                }
                else
                {
                    menu.AddDisabledItem(new GUIContent("Set as Start"));
                }

                // Set as concurrent state
                if (m_State.fsm != null && !(m_State is InternalAnyState))
                {
                    if (m_IsConcurrent)
                    {
                        menu.AddItem(new GUIContent("Set as Not Concurrent"), false, delegate() { StateUtility.RemoveConcurrentState(m_State.fsm); this.Refresh(); });
                    }
                    else
                    {
                        menu.AddItem(new GUIContent("Set as Concurrent"), false, delegate() { StateUtility.SetAsConcurrent(m_State); this.Refresh(); });
                    }
                }
                else
                {
                    menu.AddDisabledItem(new GUIContent("Set as Concurrent"));
                }

                // Set as enabled
                if (m_State.fsm != null /*&& m_State.fsm.enabled*/ && Application.isPlaying && !(m_State is InternalAnyState))
                {
                    menu.AddItem(new GUIContent("Set as Enabled"), false, delegate() { m_State.enabled = true; });
                }
                else
                {
                    menu.AddDisabledItem(new GUIContent("Set as Enabled"));
                }

                // Add Transitions
                // Add none
                menu.AddItem(new GUIContent("Add Transition/None"), false, delegate() { StateUtility.AddTransition(m_State, 0); CreateTransitionGUIs(); });

                // Add blackboard events
                var blackboard = m_State.blackboard;
                if (blackboard != null)
                {
                    foreach (var fsmEvent in blackboard.fsmEvents)
                    {
                        int eventId = fsmEvent.id;
                        menu.AddItem(new GUIContent("Add Transition/" + fsmEvent.name), false, delegate() { StateUtility.AddTransition(m_State, eventId); CreateTransitionGUIs(); });
                    }
                }

                // Add GlobalBlackboard events
                // This is not The GlobalBlackboard?
                if (InternalGlobalBlackboard.Instance != null && blackboard != InternalGlobalBlackboard.Instance)
                {
                    foreach (var globalEvent in InternalGlobalBlackboard.Instance.fsmEvents)
                    {
                        int eventId   = globalEvent.id;
                        var eventName = globalEvent.isSystem ? "Add Transition/System/" + globalEvent.name : "Add Transition/Global/" + globalEvent.name;
                        menu.AddItem(new GUIContent(eventName), false, delegate() { StateUtility.AddTransition(m_State, eventId); CreateTransitionGUIs(); });
                    }
                }

                // Separator
                menu.AddSeparator("");

                // Copy
                menu.AddItem(new GUIContent("Copy State"), false, delegate() { StateUtility.CopySelectedStates(); });

                // Paste
                if (StateUtility.statesToPaste != null && StateUtility.statesToPaste.Length > 0 && m_State.fsm != null)
                {
                    menu.AddItem(new GUIContent("Paste State"), false, delegate() { StateUtility.PasteStates(m_State.fsm); });
                }
                else
                {
                    menu.AddDisabledItem(new GUIContent("Paste State"));
                }

                // Duplicate
                if (m_State.fsm != null)
                {
                    menu.AddItem(new GUIContent("Duplicate State"), false, delegate()
                    {
                        var statesToPaste = new List <InternalStateBehaviour>(BehaviourWindow.activeStates);
                        if (!statesToPaste.Contains(m_State))
                        {
                            statesToPaste.Add(m_State);
                        }

                        StateUtility.CloneStates(m_State.gameObject, statesToPaste.ToArray(), m_State.fsm);
                    }
                                 );
                }
                else
                {
                    menu.AddDisabledItem(new GUIContent("Duplicate State"));
                }

                // Separator
                menu.AddSeparator("");

                // Delete
                menu.AddItem(new GUIContent("Delete"), false, delegate() { StateUtility.Destroy(m_State); this.Refresh(); });
            }
            else
            {
                menu.AddDisabledItem(new GUIContent("Set as Start"));
                menu.AddDisabledItem(new GUIContent("Set as Enabled"));
                menu.AddDisabledItem(new GUIContent("Add Transition"));
                menu.AddSeparator("");
                menu.AddDisabledItem(new GUIContent("Copy State"));
                menu.AddDisabledItem(new GUIContent("Paste State"));
                menu.AddSeparator("");
                menu.AddDisabledItem(new GUIContent("Delete"));
            }

            // Show the context menu
            menu.ShowAsContext();
        }