123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- #if UNITY_2022_2_OR_NEWER
-
- using UnityEngine;
- using UnityEditor.AI;
- using UnityEditorInternal;
- using EditorNavMeshBuilder = UnityEditor.AI.NavMeshBuilder;
- using Object = UnityEngine.Object;
- using UnityEditor;
-
- namespace Unity.AI.Navigation.Editor
- {
- [InitializeOnLoad]
- [EditorWindowTitle(title = "Navigation")]
- internal class NavigationWindow : EditorWindow
- {
- static NavigationWindow s_NavigationWindow;
-
- // Scene based bake configuration
- SerializedObject m_SettingsObject;
-
- // Project based configuration
- SerializedObject m_NavMeshProjectSettingsObject;
- SerializedProperty m_Areas;
-
- SerializedProperty m_AgentTypes;
- SerializedProperty m_SettingNames;
-
- Vector2 m_ScrollPos = Vector2.zero;
- bool m_Advanced;
-
- ReorderableList m_AreasList;
- ReorderableList m_AgentTypeList;
-
- enum Mode
- {
- AgentTypeSettings = 0,
- AreaSettings = 1,
- }
-
- Mode m_Mode = Mode.AgentTypeSettings;
-
- static class Styles
- {
- internal static readonly GUIContent k_AgentTypesHeader = EditorGUIUtility.TrTextContent("Agent Types");
- internal static readonly GUIContent k_NameLabel = EditorGUIUtility.TrTextContent("Name");
- internal static readonly GUIContent k_CostLabel = EditorGUIUtility.TrTextContent("Cost");
- internal static readonly GUIContent[] k_ModeToggles =
- {
- EditorGUIUtility.TrTextContent("Agents", "Navmesh agent settings."),
- EditorGUIUtility.TrTextContent("Areas", "Navmesh area settings."),
- };
- internal static readonly GUIStyle k_ContentMargins = new GUIStyle
- {
- padding = new RectOffset(4, 4, 4, 4)
- };
- };
-
- static NavigationWindow()
- {
- NavMeshEditorHelpers.areaSettingsClicked += OpenAreaSettings;
- NavMeshEditorHelpers.agentTypeSettingsClicked += OpenAgentSettings;
- }
-
- [MenuItem("Window/AI/Navigation", false, 1)]
- public static void SetupWindow()
- {
- var window = GetWindow<NavigationWindow>();
- window.minSize = new Vector2(300, 360);
- }
-
- static void OpenAreaSettings()
- {
- SetupWindow();
- if (s_NavigationWindow == null)
- return;
-
- s_NavigationWindow.m_Mode = Mode.AreaSettings;
- s_NavigationWindow.InitProjectSettings();
- s_NavigationWindow.InitAgentTypes();
- }
-
- static void OpenAgentSettings(int agentTypeID)
- {
- SetupWindow();
- if (s_NavigationWindow == null)
- return;
-
- s_NavigationWindow.m_Mode = Mode.AgentTypeSettings;
- s_NavigationWindow.InitProjectSettings();
- s_NavigationWindow.InitAgentTypes();
-
- s_NavigationWindow.m_AgentTypeList.index = -1;
- for (int i = 0; i < s_NavigationWindow.m_AgentTypes.arraySize; i++)
- {
- SerializedProperty agentType = s_NavigationWindow.m_AgentTypes.GetArrayElementAtIndex(i);
- SerializedProperty idProp = agentType.FindPropertyRelative("agentTypeID");
- if (idProp.intValue == agentTypeID)
- {
- s_NavigationWindow.m_AgentTypeList.index = i;
- break;
- }
- }
- }
-
- public void OnEnable()
- {
- var iconPath = $"{NavMeshComponentsGUIUtility.k_PackageEditorResourcesFolder}NavigationWindowIcon.png";
- titleContent = EditorGUIUtility.TrTextContentWithIcon("Navigation", iconPath);
- s_NavigationWindow = this;
- EditorApplication.searchChanged += Repaint;
-
- Repaint();
- }
-
- void InitProjectSettings()
- {
- if (m_NavMeshProjectSettingsObject == null)
- {
- Object obj = Unsupported.GetSerializedAssetInterfaceSingleton("NavMeshProjectSettings");
- m_NavMeshProjectSettingsObject = new SerializedObject(obj);
- }
- }
-
- void InitAreas()
- {
- if (m_Areas == null)
- {
- m_Areas = m_NavMeshProjectSettingsObject.FindProperty("areas");
- }
- if (m_AreasList == null)
- {
- m_AreasList = new ReorderableList(m_NavMeshProjectSettingsObject, m_Areas, false, true, false, false);
- m_AreasList.drawElementCallback = DrawAreaListElement;
- m_AreasList.drawHeaderCallback = DrawAreaListHeader;
- m_AreasList.elementHeight = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
- }
- }
-
- void InitAgentTypes()
- {
- if (m_AgentTypes == null)
- {
- m_AgentTypes = m_NavMeshProjectSettingsObject.FindProperty("m_Settings");
- m_SettingNames = m_NavMeshProjectSettingsObject.FindProperty("m_SettingNames");
- }
- if (m_AgentTypeList == null)
- {
- m_AgentTypeList = new ReorderableList(m_NavMeshProjectSettingsObject, m_AgentTypes, false, true, true, true);
- m_AgentTypeList.drawElementCallback = DrawAgentTypeListElement;
- m_AgentTypeList.drawHeaderCallback = DrawAgentTypeListHeader;
- m_AgentTypeList.onAddCallback = AddAgentType;
- m_AgentTypeList.onRemoveCallback = RemoveAgentType;
- m_AgentTypeList.elementHeight = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
- }
- }
-
- // This code is replicated from the navmesh debug draw code.
- int Bit(int a, int b)
- {
- return (a & (1 << b)) >> b;
- }
-
- Color GetAreaColor(int i)
- {
- if (i == 0)
- return new Color(0, 0.75f, 1.0f, 0.5f);
- int r = (Bit(i, 4) + Bit(i, 1) * 2 + 1) * 63;
- int g = (Bit(i, 3) + Bit(i, 2) * 2 + 1) * 63;
- int b = (Bit(i, 5) + Bit(i, 0) * 2 + 1) * 63;
- return new Color(r / 255.0f, g / 255.0f, b / 255.0f, 0.5f);
- }
-
- public void OnDisable()
- {
- s_NavigationWindow = null;
- EditorApplication.searchChanged -= Repaint;
- }
-
-
- void OnSelectionChange()
- {
- m_ScrollPos = Vector2.zero;
- }
-
- void ModeToggle()
- {
- EditorGUILayout.BeginHorizontal();
- GUILayout.FlexibleSpace();
- m_Mode = (Mode)GUILayout.Toolbar((int)m_Mode, Styles.k_ModeToggles, "LargeButton", GUI.ToolbarButtonSize.FitToContents);
- GUILayout.FlexibleSpace();
- EditorGUILayout.EndHorizontal();
- }
-
- static void GetAreaListRects(Rect rect, out Rect stripeRect, out Rect labelRect, out Rect nameRect, out Rect costRect)
- {
- float stripeWidth = EditorGUIUtility.singleLineHeight * 0.8f;
- float labelWidth = EditorGUIUtility.singleLineHeight * 5;
- float costWidth = EditorGUIUtility.singleLineHeight * 4;
- float nameWidth = rect.width - stripeWidth - labelWidth - costWidth;
- float x = rect.x;
- stripeRect = new Rect(x, rect.y, stripeWidth - 4, rect.height);
- x += stripeWidth;
- labelRect = new Rect(x, rect.y, labelWidth - 4, rect.height);
- x += labelWidth;
- nameRect = new Rect(x, rect.y, nameWidth - 4, rect.height);
- x += nameWidth;
- costRect = new Rect(x, rect.y, costWidth, rect.height);
- }
-
- void DrawAreaListHeader(Rect rect)
- {
- GetAreaListRects(rect, out _, out _, out Rect nameRect, out Rect costRect);
- GUI.Label(nameRect, Styles.k_NameLabel);
- GUI.Label(costRect, Styles.k_CostLabel);
- }
-
- void DrawAreaListElement(Rect rect, int index, bool selected, bool focused)
- {
- SerializedProperty areaProp = m_Areas.GetArrayElementAtIndex(index);
- if (areaProp == null)
- return;
- SerializedProperty nameProp = areaProp.FindPropertyRelative("name");
- SerializedProperty costProp = areaProp.FindPropertyRelative("cost");
- if (nameProp == null || costProp == null)
- return;
-
- rect.height -= 2; // nicer looking with selected list row and a text field in it
-
- bool builtInLayer;
- bool allowChangeName;
- bool allowChangeCost;
- switch (index)
- {
- case 0: // Default
- builtInLayer = true;
- allowChangeName = false;
- allowChangeCost = true;
- break;
- case 1: // NonWalkable
- builtInLayer = true;
- allowChangeName = false;
- allowChangeCost = false;
- break;
- case 2: // Jump
- builtInLayer = true;
- allowChangeName = false;
- allowChangeCost = true;
- break;
- default:
- builtInLayer = false;
- allowChangeName = true;
- allowChangeCost = true;
- break;
- }
-
- GetAreaListRects(rect, out Rect stripeRect, out Rect labelRect, out Rect nameRect, out Rect costRect);
-
- bool oldEnabled = GUI.enabled;
- Color color = GetAreaColor(index);
- Color dimmed = new Color(color.r * 0.1f, color.g * 0.1f, color.b * 0.1f, 0.6f);
- EditorGUI.DrawRect(stripeRect, color);
-
- EditorGUI.DrawRect(new Rect(stripeRect.x, stripeRect.y, 1, stripeRect.height), dimmed);
- EditorGUI.DrawRect(new Rect(stripeRect.x + stripeRect.width - 1, stripeRect.y, 1, stripeRect.height), dimmed);
- EditorGUI.DrawRect(new Rect(stripeRect.x + 1, stripeRect.y, stripeRect.width - 2, 1), dimmed);
- EditorGUI.DrawRect(new Rect(stripeRect.x + 1, stripeRect.y + stripeRect.height - 1, stripeRect.width - 2, 1), dimmed);
-
- if (builtInLayer)
- GUI.Label(labelRect, EditorGUIUtility.TrTempContent("Built-in " + index));
- else
- GUI.Label(labelRect, EditorGUIUtility.TrTempContent("User " + index));
-
- int oldIndent = EditorGUI.indentLevel;
- EditorGUI.indentLevel = 0;
-
- GUI.enabled = oldEnabled && allowChangeName;
- EditorGUI.PropertyField(nameRect, nameProp, GUIContent.none);
-
- GUI.enabled = oldEnabled && allowChangeCost;
- EditorGUI.PropertyField(costRect, costProp, GUIContent.none);
-
- GUI.enabled = oldEnabled;
-
- EditorGUI.indentLevel = oldIndent;
- }
-
- static void AddAgentType(ReorderableList list)
- {
- UnityEngine.AI.NavMesh.CreateSettings();
- list.index = UnityEngine.AI.NavMesh.GetSettingsCount() - 1;
- }
-
- void RemoveAgentType(ReorderableList list)
- {
- SerializedProperty agentTypeProp = m_AgentTypes.GetArrayElementAtIndex(list.index);
- if (agentTypeProp == null)
- return;
- SerializedProperty idProp = agentTypeProp.FindPropertyRelative("agentTypeID");
- if (idProp == null)
- return;
- // Cannot delete default.
- if (idProp.intValue == 0)
- return;
-
- m_SettingNames.DeleteArrayElementAtIndex(list.index);
- ReorderableList.defaultBehaviours.DoRemoveButton(list);
- }
-
- static void DrawAgentTypeListHeader(Rect rect)
- {
- GUI.Label(rect, Styles.k_AgentTypesHeader);
- }
-
- void DrawAgentTypeListElement(Rect rect, int index, bool selected, bool focused)
- {
- SerializedProperty agentProp = m_AgentTypes.GetArrayElementAtIndex(index);
- if (agentProp == null)
- return;
- SerializedProperty idProp = agentProp.FindPropertyRelative("agentTypeID");
- if (idProp == null)
- return;
-
- rect.height -= 2; // nicer looking with selected list row and a text field in it
-
- bool isDefault = idProp.intValue == 0;
- using (new EditorGUI.DisabledScope(isDefault))
- {
- var settingsName = UnityEngine.AI.NavMesh.GetSettingsNameFromID(idProp.intValue);
- GUI.Label(rect, EditorGUIUtility.TrTempContent(settingsName));
- }
- }
-
- public void OnGUI()
- {
- EditorGUILayout.Space();
- ModeToggle();
- EditorGUILayout.Space();
-
- InitProjectSettings();
-
- m_ScrollPos = EditorGUILayout.BeginScrollView(m_ScrollPos);
- switch (m_Mode)
- {
- case Mode.AreaSettings:
- AreaSettings();
- break;
- case Mode.AgentTypeSettings:
- AgentTypeSettings();
- break;
- }
- EditorGUILayout.EndScrollView();
- }
-
- void AreaSettings()
- {
- if (m_Areas == null)
- InitAreas();
- m_NavMeshProjectSettingsObject.Update();
-
- using (new GUILayout.VerticalScope(Styles.k_ContentMargins))
- {
- m_AreasList.DoLayoutList();
- }
-
- m_NavMeshProjectSettingsObject.ApplyModifiedProperties();
- }
-
- void AgentTypeSettings()
- {
- if (m_AgentTypes == null)
- InitAgentTypes();
- m_NavMeshProjectSettingsObject.Update();
-
- if (m_AgentTypeList.index < 0)
- m_AgentTypeList.index = 0;
-
- using (new GUILayout.VerticalScope(Styles.k_ContentMargins))
- {
- m_AgentTypeList.DoLayoutList();
- }
-
- if (m_AgentTypeList.index >= 0 && m_AgentTypeList.index < m_AgentTypes.arraySize)
- {
- SerializedProperty nameProp = m_SettingNames.GetArrayElementAtIndex(m_AgentTypeList.index);
- SerializedProperty selectedAgentType = m_AgentTypes.GetArrayElementAtIndex(m_AgentTypeList.index);
-
- SerializedProperty radiusProp = selectedAgentType.FindPropertyRelative("agentRadius");
- SerializedProperty heightProp = selectedAgentType.FindPropertyRelative("agentHeight");
- SerializedProperty stepHeightProp = selectedAgentType.FindPropertyRelative("agentClimb");
- SerializedProperty maxSlopeProp = selectedAgentType.FindPropertyRelative("agentSlope");
- SerializedProperty ledgeDropHeightProp = selectedAgentType.FindPropertyRelative("ledgeDropHeight");
- SerializedProperty jumpDistanceProp = selectedAgentType.FindPropertyRelative("maxJumpAcrossDistance");
-
- const float kDiagramHeight = 120.0f;
- Rect agentDiagramRect = EditorGUILayout.GetControlRect(false, kDiagramHeight);
- NavMeshEditorHelpers.DrawAgentDiagram(agentDiagramRect, radiusProp.floatValue, heightProp.floatValue, stepHeightProp.floatValue, maxSlopeProp.floatValue);
-
- EditorGUILayout.PropertyField(nameProp, EditorGUIUtility.TrTempContent("Name"));
- EditorGUILayout.PropertyField(radiusProp, EditorGUIUtility.TrTempContent("Radius"));
- EditorGUILayout.PropertyField(heightProp, EditorGUIUtility.TrTempContent("Height"));
- EditorGUILayout.PropertyField(stepHeightProp, EditorGUIUtility.TrTempContent("Step Height"));
-
- const float kMaxSlopeAngle = 60.0f;
- EditorGUILayout.Slider(maxSlopeProp, 0.0f, kMaxSlopeAngle, EditorGUIUtility.TrTextContent("Max Slope"));
-
- EditorGUILayout.Space();
- EditorGUILayout.LabelField(EditorGUIUtility.TrTempContent("Generated Links"), EditorStyles.boldLabel);
- EditorGUILayout.PropertyField(ledgeDropHeightProp, EditorGUIUtility.TrTempContent("Drop Height"));
- EditorGUILayout.PropertyField(jumpDistanceProp, EditorGUIUtility.TrTempContent("Jump Distance"));
- }
-
- EditorGUILayout.Space();
-
- m_NavMeshProjectSettingsObject.ApplyModifiedProperties();
- }
- }
- }
-
- #endif
|