void OnGUI() { foreach (var obj in Selection.objects) { if (obj is StateMachineDefinition) { def = (StateMachineDefinition)obj; break; } } if (!Application.isPlaying) { ShowSidebar(); } Rect viewportRect = new Rect(0, 0, position.width - sideWidth, position.height); EditorGUI.DrawRect(viewportRect, bgColor); GUI.EndGroup(); Rect clippedArea = new Rect(0, 0, position.width - sideWidth, position.height); clippedArea.size /= zoom; clippedArea.y += editorWindowTabHeight / zoom; GUI.BeginGroup(clippedArea); bool repaint = false; if (def != null) { Event cur = Event.current; Matrix4x4 gm = GUI.matrix; GUI.matrix = Matrix4x4.Scale(new Vector3(zoom, zoom, 1)); UpdateView(ref repaint); if (!Application.isPlaying) { 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(ToWorld(cur.mousePosition)); var selectedTr = def.SelectTransition(ToWorld(cur.mousePosition)); if (selectedTr.t1 == null) { if (selected != lastSelectedState) { repaint = true; lastSelectedState = selected; } if (lastSelectedTr != null) { lastSelectedTr = null; repaint = true; } } else { if (selectedTr.t2 != lastSelectedTr) { repaint = true; lastSelectedTr = selectedTr.t2; } if (lastSelectedState != null) { lastSelectedState = null; repaint = true; } } if (cur.type == EventType.MouseDown) { if (cur.button == 0) { if (selectedTr.t1 != null) { editingTransition = selectedTr; editingState = null; repaint = true; } else if (selected != null) { editingState = selected; editingTransition.t1 = null; editingTransition.t2 = null; repaint = true; if (cur.clickCount == 1) { op = new MoveStateOperation(def, this, selected); } else if (cur.clickCount == 2) { op = new RenameStateOperation(def, this, selected); } } else { editingState = null; editingTransition.t1 = null; editingTransition.t2 = null; repaint = true; } } 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 = ToWorld((cur.mousePosition - Vector2.up * editorWindowTabHeight) / zoom); MoveStateOperation.Snap(ref s.position); op = new RenameStateOperation(def, this, s); EditorUtility.SetDirty(def); dirty = true; }); GUI.EndGroup(); menu.ShowAsContext(); GUI.BeginGroup(clippedArea); } 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; }); GUI.EndGroup(); menu.ShowAsContext(); GUI.BeginGroup(clippedArea); } 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("Rename State"), false, () => { op = new RenameStateOperation(def, this, selected); }); menu.AddItem(new GUIContent("Add Transition"), false, () => { op = new MakeTransitionOperation(def, this, selected); }); StateMachineDefinition.State parent = def.GetState(selected.parent); if (parent == null) { if (selected.name != def.defaultState) { menu.AddItem(new GUIContent("Make Default State"), false, () => { def.defaultState = selected.name; dirty = true; repaint = true; }); } } else { if (selected.name != parent.localDefault) { menu.AddItem(new GUIContent("Make Local Default"), false, () => { parent.localDefault = selected.name; dirty = true; repaint = true; }); } } if (selected.hasChildren) { menu.AddItem(new GUIContent("Remove Sub-Machine"), false, () => { def.RemoveSub(selected, MoveStateOperation.snap * 2); }); menu.AddItem(new GUIContent("Create Child State"), false, () => { var s = def.AddState(); s.position = ToWorld((cur.mousePosition - Vector2.up * editorWindowTabHeight) / zoom); def.SetStateParent(s, selected, MoveStateOperation.snap); MoveStateOperation.Snap(ref s.position); op = new RenameStateOperation(def, this, s); EditorUtility.SetDirty(def); dirty = true; }); } else { menu.AddItem(new GUIContent("Make Sub-Machine"), false, () => { def.CreateSub(selected, MoveStateOperation.snap * 2); }); } GUI.EndGroup(); menu.ShowAsContext(); GUI.BeginGroup(clippedArea); } } } } } if (Event.current.type != EventType.Repaint && (repaint || (op != null && op.repaint))) { Repaint(); } Handles.BeginGUI(); Handles.color = lineColor; Vector2 sz = scroll / zoom; for (float x = -sz.x % MoveStateOperation.snap; x < clippedArea.width; x += MoveStateOperation.snap) { Handles.DrawLine(new Vector3(x, 0), new Vector3(x, clippedArea.height)); } for (float y = -sz.y % MoveStateOperation.snap; y < clippedArea.height; y += MoveStateOperation.snap) { Handles.DrawLine(new Vector3(0, y), new Vector3(clippedArea.width, y)); } if (Application.isPlaying) { if (observing == null || observing.gameObject != Selection.activeGameObject) { if (Selection.activeGameObject) { observing = Selection.activeGameObject.GetComponent <StateMachine>(); } if (observing == null) { observing = (StateMachine)FindObjectOfType(typeof(StateMachine).Assembly.GetType(def.name)); } } } else if (!Application.isPlaying) { observing = null; } Color oldColor = GUI.color; if (def.states != null) { foreach (var state in def.states) { if (op == null || op.state != state || op.showBaseGUI) { string s = state.name; var parent = def.GetState(state.parent); if (parent == null && def.defaultState == s) { s += "\n<default state>"; } else if (parent != null && parent.localDefault == s) { s += "\n<local default>"; } Rect rect = state.rect; rect.position = ToScreen(rect.position); GUI.SetNextControlName("StateButton"); if (observing && cur.type == EventType.Repaint) { if (observing.IsStateActive(state.name)) { GUI.color = new Color(0.5f, 0.7f, 1.0f); } else if (observing.IsStateRemembered(state.name)) { GUI.color = new Color(0.9f, 0.8f, 1.0f); } else { GUI.color = oldColor; } } if (!state.hasChildren) { if (state != editingState) { GUI.Button(rect, s); } else { GUI.Button(rect, ""); var style = new GUIStyle(GUI.skin.label); style.alignment = TextAnchor.MiddleCenter; style.normal.textColor = Color.blue; style.fontStyle = FontStyle.Bold; GUI.Label(rect, s, style); } } else { GUI.Button(rect, ""); var style = new GUIStyle(GUI.skin.label); style.alignment = TextAnchor.UpperCenter; if (state == editingState) { style.normal.textColor = Color.blue; style.fontStyle = FontStyle.Bold; } GUI.Label(rect, s, style); Rect innerRect = rect; innerRect.xMin += 4; innerRect.xMax -= 4; innerRect.yMin += 32; innerRect.yMax -= 4; GUI.color = oldColor; EditorGUI.DrawRect(innerRect, bgColor); Handles.color = lineColor; for (float x = rect.xMin + MoveStateOperation.snap; x < rect.xMax; x += MoveStateOperation.snap) { Handles.DrawLine(new Vector3(x, innerRect.yMin), new Vector3(x, innerRect.yMax)); } for (float y = rect.yMin + MoveStateOperation.snap * 2; y < rect.yMax; y += MoveStateOperation.snap) { Handles.DrawLine(new Vector3(innerRect.xMin, y), new Vector3(innerRect.xMax, y)); } } } if (op != null && op.state == state) { op.OnGUI(); } } foreach (var from in def.states) { if (from.transitions != null) { foreach (var tr in from.transitions) { if (Application.isPlaying) { Handles.color = Color.black; if (observing) { float t = Time.unscaledTime - observing.TransitionLastTime(from.name, tr.to); if (t < 0.5f) { Handles.color = Color.Lerp(Color.black, Color.green, 1.0f - t * 2); } } } else { 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 = ToScreen(line.t1); Vector2 dest = ToScreen(line.t2); 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 * 6); } } } } } Handles.EndGUI(); GUI.matrix = gm; } else if (op != null) { op.Cancel(); op = null; } }