Beispiel #1
0
        public static void GenerateImplClass(StateMachineDefinition def, string path)
        {
            string className = Path.GetFileNameWithoutExtension(path);

            string generated = string.Format(implClassTemplate, className, def.name, GetFunctionDeclarations(def, true));

            StreamWriter outStream = new StreamWriter(path);

            outStream.Write(generated);
            outStream.Close();
            AssetDatabase.Refresh();
        }
Beispiel #2
0
        public static string GetTransitionInitializers(StateMachineDefinition def)
        {
            string str = "";

            foreach (var state in def.states)
            {
                for (int i = 0; i < state.transitions.Count; i++)
                {
                    str += GetTransitionInitializer(state, state.transitions[i], i);
                }
            }
            return(str);
        }
        public override void OnInspectorGUI()
        {
            StateMachineDefinition myTarget = (StateMachineDefinition)target;

            if (GUILayout.Button("Open State Machine Editor"))
            {
                StateMachineEditorWindow.def = myTarget;
                StateMachineEditorWindow.ShowWindow();
            }

            serializedObject.Update();
            DrawPropertiesExcluding(serializedObject, "baseClass");
            serializedObject.ApplyModifiedProperties();
        }
Beispiel #4
0
        private static string GetStateEnums(StateMachineDefinition def)
        {
            string str = "";

            for (int i = 0; i < def.states.Count; i++)
            {
                str += def.states[i].name;

                if (i < def.states.Count - 1)
                {
                    str += ", ";
                }
            }

            return(str);
        }
Beispiel #5
0
        public static void GenerateAbstractClass(StateMachineDefinition def)
        {
            string generated = string.Format(abstractClassTemplate, def.name, GetStateEnums(def), GetStateInitializers(def), GetTransitionInitializers(def), GetFunctionDeclarations(def), def.baseClass);

            string defPath = AssetDatabase.GetAssetPath(def);

            if (defPath.Length > 0)
            {
                string newPath = defPath.Substring(0, defPath.LastIndexOf(".")) + ".cs";

                StreamWriter outStream = new StreamWriter(newPath);
                outStream.Write(generated);
                outStream.Close();
                AssetDatabase.Refresh();
            }
        }
Beispiel #6
0
        public static string GetStateInitializers(StateMachineDefinition def)
        {
            string str = "        states = new State[" + def.states.Count + "];\n\n";

            for (int i = 0; i < def.states.Count; i++)
            {
                str += GetStateInitializer(def.states[i], i);
            }
            if (def.defaultState.Length > 0)
            {
                str += "        currentState = state" + def.defaultState + ";\n";
            }
            else
            {
                str += "        currentState = states[0];\n";
            }
            return(str);
        }
Beispiel #7
0
        public static string GetFunctionDeclarations(StateMachineDefinition def, bool over = false)
        {
            string vo = over ? "override" : "virtual";


            string str = "";

            foreach (var state in def.states)
            {
                if (state.hasEnter)
                {
                    str += "    protected " + vo + " void StateEnter_" + state.name + "() { }\n";
                }

                if (state.hasDuring)
                {
                    str += "    protected " + vo + " void State_" + state.name + "() { }\n";
                }

                if (state.hasExit)
                {
                    str += "    protected " + vo + " void StateExit_" + state.name + "() { }\n";
                }
            }

            str += "\n";

            foreach (var state in def.states)
            {
                foreach (var trans in state.transitions)
                {
                    str += "    protected " + vo + " bool TransitionCond_" + state.name + "_" + trans.to + "() { return false; }\n";

                    if (trans.hasNotify)
                    {
                        str += "    protected " + vo + " void TransitionNotify_" + state.name + "_" + trans.to + "() { }\n";
                    }
                }
            }

            return(str);
        }
Beispiel #8
0
 public Operation(StateMachineDefinition definition, StateMachineDefinition.State state)
 {
     this.definition = definition;
     this.state      = state;
 }
 public RenameStateOperation(StateMachineDefinition def, StateMachineDefinition.State state) : base(def, state)
 {
     name        = state.name;
     showBaseGUI = false;
 }
 public MakeTransitionOperation(StateMachineDefinition def, StateMachineDefinition.State state) : base(def, state)
 {
     showBaseGUI = true;
 }
Beispiel #11
0
 public MoveStateOperation(StateMachineDefinition def, StateMachineDefinition.State state) : base(def, state)
 {
     showBaseGUI = true;
     start       = state.position;
     move        = Vector2.zero;
 }
        void OnGUI()
        {
            ResizeScrollView();
            Rect viewportRect = new Rect(0, 0, position.width - sidePanelWidth, position.height);

            EditorGUI.DrawRect(viewportRect, bgColor);
            bool repaint = false;

            foreach (var obj in Selection.objects)
            {
                if (obj is StateMachineDefinition)
                {
                    def = (StateMachineDefinition)obj;
                    break;
                }
            }

            if (def != null)
            {
                bool showSide = true;

                Event cur = Event.current;

                if (op != null)
                {
                    if (def != op.definition)
                    {
                        op.Cancel();
                        op = null;
                    }
                    else
                    {
                        op.Update();

                        if (op.done)
                        {
                            op      = null;
                            repaint = true;
                            EditorUtility.SetDirty(def);
                            dirty = true;
                        }
                    }
                }
                else
                {
                    var selected   = def.SelectState(cur.mousePosition + scrollPos);
                    var selectedTr = def.SelectTransition(cur.mousePosition + scrollPos);

                    if (selected == null)
                    {
                        if (selectedTr.t2 != lastSelectedTr)
                        {
                            repaint        = true;
                            lastSelectedTr = selectedTr.t2;
                        }

                        if (lastSelectedState != null)
                        {
                            lastSelectedState = null;
                            repaint           = true;
                        }
                    }
                    else
                    {
                        if (selected != lastSelectedState)
                        {
                            repaint           = true;
                            lastSelectedState = selected;
                        }

                        if (lastSelectedTr != null)
                        {
                            lastSelectedTr = null;
                            repaint        = true;
                        }
                    }

                    if (viewportRect.Contains(cur.mousePosition))
                    {
                        if (cur.type == EventType.MouseDown)
                        {
                            if (cur.button == 0)
                            {
                                if (selected != null)
                                {
                                    editingState         = selected;
                                    editingTransition.t1 = null;
                                    editingTransition.t2 = null;
                                    repaint  = true;
                                    showSide = false;


                                    if (cur.clickCount == 1)
                                    {
                                        op = new MoveStateOperation(def, selected);
                                    }
                                    else if (cur.clickCount == 2)
                                    {
                                        op = new RenameStateOperation(def, selected);
                                    }
                                }
                                else if (selectedTr.t1 != null)
                                {
                                    editingTransition = selectedTr;
                                    editingState      = null;
                                    repaint           = true;
                                    showSide          = false;
                                }
                                else
                                {
                                    editingState         = null;
                                    editingTransition.t1 = null;
                                    editingTransition.t2 = null;
                                    repaint  = true;
                                    showSide = false;
                                }
                            }
                            else if (cur.button == 1)
                            {
                                if (selected == null && lastSelectedTr == null)
                                {
                                    GenericMenu menu = new GenericMenu();

                                    menu.AddItem(new GUIContent("Create State"), false, () => {
                                        var s      = def.AddState();
                                        s.position = cur.mousePosition;
                                        op         = new RenameStateOperation(def, s);
                                        EditorUtility.SetDirty(def);
                                        dirty = true;
                                    });

                                    menu.ShowAsContext();
                                }
                                else if (selected != null)
                                {
                                    GenericMenu menu = new GenericMenu();

                                    menu.AddItem(new GUIContent("Delete State"), false, () => {
                                        def.RemoveState(selected);
                                        EditorUtility.SetDirty(def);
                                        dirty   = true;
                                        repaint = true;
                                    });

                                    menu.AddItem(new GUIContent("Add Transition"), false, () => {
                                        op = new MakeTransitionOperation(def, selected);
                                    });

                                    if (selected.name != def.defaultState)
                                    {
                                        menu.AddItem(new GUIContent("Make Default State"), false, () => {
                                            def.defaultState = selected.name;
                                            dirty            = true;
                                            repaint          = true;
                                        });
                                    }

                                    menu.ShowAsContext();
                                }
                                else if (selectedTr.t1 != null)
                                {
                                    GenericMenu menu = new GenericMenu();

                                    menu.AddItem(new GUIContent("Remove Transition"), false, () => {
                                        selectedTr.t1.RemoveTransition(selectedTr.t2);
                                        EditorUtility.SetDirty(def);
                                        dirty   = true;
                                        repaint = true;
                                    });

                                    menu.ShowAsContext();
                                }
                            }
                        }
                        else if (cur.type == EventType.MouseDrag && cur.button == 2)
                        {
                            scrollPos -= cur.delta;
                            repaint    = true;
                        }
                        else if (cur.type == EventType.KeyDown && cur.keyCode == KeyCode.F)
                        {
                            var state = def.GetState(def.defaultState);
                            if (state == null && def.states.Count > 0)
                            {
                                state = def.states[0];
                            }

                            if (state != null)
                            {
                                scrollPos = state.position - viewportRect.size / 2;
                                repaint   = true;
                            }
                        }
                    }
                }

                if (Event.current.type != EventType.Repaint && (repaint || (op != null && op.repaint)))
                {
                    Repaint();
                }

                Handles.BeginGUI();

                Handles.color = lineColor;
                for (float x = -scrollPos.x % MoveStateOperation.snap; x < viewportRect.width; x += MoveStateOperation.snap)
                {
                    Handles.DrawLine(new Vector3(x, 0), new Vector3(x, viewportRect.height));
                }

                for (float y = -scrollPos.y % MoveStateOperation.snap; y < viewportRect.height; y += MoveStateOperation.snap)
                {
                    Handles.DrawLine(new Vector3(0, y), new Vector3(viewportRect.width, y));
                }

                foreach (var from in def.states)
                {
                    if (from.transitions != null)
                    {
                        foreach (var tr in from.transitions)
                        {
                            if (tr != lastSelectedTr && tr != editingTransition.t2)
                            {
                                Handles.color = Color.black;
                            }
                            else
                            {
                                Handles.color = Color.blue;
                            }

                            if (def.GetState(tr.to) != null)
                            {
                                var     line = def.GetTransitionPoints(from, tr);
                                Vector2 src  = line.t1 - scrollPos;
                                Vector2 dest = line.t2 - scrollPos;

                                Vector2 v     = (dest - src).normalized;
                                Vector2 ortho = new Vector2(v.y, -v.x);

                                Vector2 arrow = ortho - v;
                                Vector2 mid   = (src + dest) / 2;

                                Handles.DrawAAPolyLine(3, src, dest);
                                Handles.DrawAAPolyLine(3, mid + v * 5, mid + arrow * 10);
                            }
                        }
                    }
                }

                Handles.EndGUI();

                foreach (var state in def.states)
                {
                    if (op == null || op.state != state || op.showBaseGUI)
                    {
                        string s = state.name;
                        if (def.defaultState == s)
                        {
                            s += "\n<default state>";
                        }

                        Rect rect = state.rect;
                        rect.position -= scrollPos;

                        if (state != lastSelectedState && state != editingState)
                        {
                            GUI.Button(rect, s);
                        }
                        else
                        {
                            GUI.Button(rect, "");

                            var centeredStyle = new GUIStyle(GUI.skin.label);
                            centeredStyle.alignment        = TextAnchor.MiddleCenter;
                            centeredStyle.normal.textColor = Color.blue;
                            centeredStyle.fontStyle        = FontStyle.Bold;

                            GUI.Label(rect, s, centeredStyle);
                        }
                    }

                    if (op != null && op.state == state)
                    {
                        op.OnGUI();
                    }
                }

                if (showSide)
                {
                    EditorGUI.DrawRect(new Rect(position.width - sidePanelWidth, 0, sidePanelWidth, position.height), panelColor);


                    float padding = 20;
                    GUILayout.BeginArea(new Rect(position.width - sidePanelWidth + padding, padding, sidePanelWidth - padding * 2, position.height - padding * 2));
                    EditorGUILayout.BeginVertical();
                    float w = EditorGUIUtility.labelWidth;
                    EditorGUIUtility.labelWidth = 1;

                    if (GUILayout.Button(dirty ? "Save *" : "Save"))
                    {
                        AssetDatabase.SaveAssets();
                        dirty = false;
                        StateMachineClassGenerator.GenerateAbstractClass(def);
                    }

                    if (GUILayout.Button("New Impl Class..."))
                    {
                        var path = EditorUtility.SaveFilePanelInProject("Save new class", def.name + "Impl.cs", "cs", "Enter a name for the new impl class");
                        if (path.Length > 0)
                        {
                            StateMachineClassGenerator.GenerateImplClass(def, path);
                        }
                    }

                    if (types == null)
                    {
                        types = typeof(StateMachine).Assembly.GetTypes()
                                .Where(p => !p.IsGenericType && typeof(StateMachine).IsAssignableFrom(p))
                                .Select(t => t.FullName).ToArray();
                    }

                    int index = Array.IndexOf(types, def.baseClass);
                    if (index < 0)
                    {
                        index = Array.IndexOf(types, typeof(StateMachine).FullName);
                    }
                    int prev = index;

                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Base Class");
                    index = EditorGUILayout.Popup(index, types);

                    if (prev != index)
                    {
                        dirty = true;
                    }

                    EditorGUILayout.EndHorizontal();
                    def.baseClass = types[index];

                    if (editingState != null)
                    {
                        EditorGUILayout.LabelField("State " + editingState.name);
                        EditorGUILayout.LabelField("State Events", EditorStyles.boldLabel);

                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField("Enter: ");
                        bool enter = EditorGUILayout.Toggle(editingState.hasEnter);
                        EditorGUILayout.EndHorizontal();

                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField("During: ");
                        bool during = EditorGUILayout.Toggle(editingState.hasDuring);
                        EditorGUILayout.EndHorizontal();

                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField("Exit: ");
                        bool exit = EditorGUILayout.Toggle(editingState.hasExit);
                        EditorGUILayout.EndHorizontal();


                        if (enter != editingState.hasEnter || during != editingState.hasDuring || exit != editingState.hasExit)
                        {
                            editingState.hasEnter  = enter;
                            editingState.hasDuring = during;
                            editingState.hasExit   = exit;

                            dirty = true;
                            EditorUtility.SetDirty(def);
                        }
                    }
                    else if (editingTransition.t1 != null)
                    {
                        EditorGUILayout.LabelField("Transition From " + editingTransition.t1.name + " To " + editingTransition.t2.to);
                        EditorGUILayout.LabelField("Transition Events", EditorStyles.boldLabel);

                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField("Notify: ");
                        bool notify = EditorGUILayout.Toggle(editingTransition.t2.hasNotify);
                        EditorGUILayout.EndHorizontal();

                        if (notify != editingTransition.t2.hasNotify)
                        {
                            editingTransition.t2.hasNotify = notify;

                            dirty = true;
                            EditorUtility.SetDirty(def);
                        }
                    }

                    EditorGUILayout.EndVertical();
                    EditorGUIUtility.labelWidth = w;

                    GUILayout.EndArea();
                }
            }
            else if (op != null)
            {
                op.Cancel();
                op = null;
            }
        }