Aucune description
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

NavMeshComponentsGUIUtility.cs 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. using UnityEditor;
  2. using UnityEditor.AI;
  3. using UnityEngine;
  4. using UnityEngine.AI;
  5. namespace Unity.AI.Navigation.Editor
  6. {
  7. /// <summary> Class containing a set of utility functions meant for presenting information from the NavMeshComponents into the GUI. </summary>
  8. public static class NavMeshComponentsGUIUtility
  9. {
  10. internal const string k_PackageEditorResourcesFolder = "Packages/com.unity.ai.navigation/EditorResources/";
  11. /// <summary> Displays a GUI element for selecting the area type used by a <see cref="NavMeshSurface"/>, <see cref="NavMeshLink"/>, <see cref="NavMeshModifier"/> or <see cref="NavMeshModifierVolume"/>. </summary>
  12. /// <param name="labelName"></param>
  13. /// <param name="areaProperty"></param>
  14. public static void AreaPopup(string labelName, SerializedProperty areaProperty)
  15. {
  16. var areaIndex = -1;
  17. var areaNames = GameObjectUtility.GetNavMeshAreaNames();
  18. for (var i = 0; i < areaNames.Length; i++)
  19. {
  20. var areaValue = GameObjectUtility.GetNavMeshAreaFromName(areaNames[i]);
  21. if (areaValue == areaProperty.intValue)
  22. areaIndex = i;
  23. }
  24. ArrayUtility.Add(ref areaNames, "");
  25. ArrayUtility.Add(ref areaNames, "Open Area Settings...");
  26. var rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight);
  27. EditorGUI.BeginProperty(rect, GUIContent.none, areaProperty);
  28. EditorGUI.BeginChangeCheck();
  29. areaIndex = EditorGUI.Popup(rect, labelName, areaIndex, areaNames);
  30. if (EditorGUI.EndChangeCheck())
  31. {
  32. if (areaIndex >= 0 && areaIndex < areaNames.Length - 2)
  33. areaProperty.intValue = GameObjectUtility.GetNavMeshAreaFromName(areaNames[areaIndex]);
  34. else if (areaIndex == areaNames.Length - 1)
  35. NavMeshEditorHelpers.OpenAreaSettings();
  36. }
  37. EditorGUI.EndProperty();
  38. }
  39. /// <summary> Displays a GUI element for selecting the agent type used by a <see cref="NavMeshSurface"/> or <see cref="NavMeshLink"/>. </summary>
  40. /// <param name="labelName"></param>
  41. /// <param name="agentTypeID"></param>
  42. public static void AgentTypePopup(string labelName, SerializedProperty agentTypeID)
  43. {
  44. var index = -1;
  45. var count = NavMesh.GetSettingsCount();
  46. var agentTypeNames = new string[count + 2];
  47. for (var i = 0; i < count; i++)
  48. {
  49. var id = NavMesh.GetSettingsByIndex(i).agentTypeID;
  50. var name = NavMesh.GetSettingsNameFromID(id);
  51. agentTypeNames[i] = name;
  52. if (id == agentTypeID.intValue)
  53. index = i;
  54. }
  55. agentTypeNames[count] = "";
  56. agentTypeNames[count + 1] = "Open Agent Settings...";
  57. bool validAgentType = index != -1;
  58. if (!validAgentType)
  59. {
  60. EditorGUILayout.HelpBox("Agent Type invalid.", MessageType.Warning);
  61. }
  62. var rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight);
  63. EditorGUI.BeginProperty(rect, GUIContent.none, agentTypeID);
  64. EditorGUI.BeginChangeCheck();
  65. index = EditorGUI.Popup(rect, labelName, index, agentTypeNames);
  66. if (EditorGUI.EndChangeCheck())
  67. {
  68. if (index >= 0 && index < count)
  69. {
  70. var id = NavMesh.GetSettingsByIndex(index).agentTypeID;
  71. agentTypeID.intValue = id;
  72. }
  73. else if (index == count + 1)
  74. {
  75. NavMeshEditorHelpers.OpenAgentSettings(-1);
  76. }
  77. }
  78. EditorGUI.EndProperty();
  79. }
  80. // Agent mask is a set (internally array/list) of agentTypeIDs.
  81. // It is used to describe which agents modifiers apply to.
  82. // There is a special case of "None" which is an empty array.
  83. // There is a special case of "All" which is an array of length 1, and value of -1.
  84. /// <summary> Displays a GUI element for selecting multiple agent types for which a <see cref="NavMeshModifier"/> or <see cref="NavMeshModifierVolume"/> can influence the NavMesh. </summary>
  85. /// <param name="labelName"></param>
  86. /// <param name="agentMask"></param>
  87. public static void AgentMaskPopup(string labelName, SerializedProperty agentMask)
  88. {
  89. // Contents of the dropdown box.
  90. string popupContent = "";
  91. if (agentMask.hasMultipleDifferentValues)
  92. popupContent = "\u2014";
  93. else
  94. popupContent = GetAgentMaskLabelName(agentMask);
  95. var content = new GUIContent(popupContent);
  96. var popupRect = GUILayoutUtility.GetRect(content, EditorStyles.popup);
  97. EditorGUI.BeginProperty(popupRect, GUIContent.none, agentMask);
  98. popupRect = EditorGUI.PrefixLabel(popupRect, 0, new GUIContent(labelName));
  99. bool pressed = GUI.Button(popupRect, content, EditorStyles.popup);
  100. if (pressed)
  101. {
  102. var show = !agentMask.hasMultipleDifferentValues;
  103. var showNone = show && agentMask.arraySize == 0;
  104. var showAll = show && IsAll(agentMask);
  105. var menu = new GenericMenu();
  106. menu.AddItem(new GUIContent("None"), showNone, SetAgentMaskNone, agentMask);
  107. menu.AddItem(new GUIContent("All"), showAll, SetAgentMaskAll, agentMask);
  108. menu.AddSeparator("");
  109. var count = NavMesh.GetSettingsCount();
  110. for (var i = 0; i < count; i++)
  111. {
  112. var id = NavMesh.GetSettingsByIndex(i).agentTypeID;
  113. var sname = NavMesh.GetSettingsNameFromID(id);
  114. var showSelected = show && AgentMaskHasSelectedAgentTypeID(agentMask, id);
  115. var userData = new object[] { agentMask, id, !showSelected };
  116. menu.AddItem(new GUIContent(sname), showSelected, ToggleAgentMaskItem, userData);
  117. }
  118. menu.DropDown(popupRect);
  119. }
  120. EditorGUI.EndProperty();
  121. }
  122. /// <summary> Creates a new GameObject as a child of another one and selects it immediately. </summary>
  123. /// <param name="suggestedName"></param>
  124. /// <param name="parent"></param>
  125. /// <returns></returns>
  126. public static GameObject CreateAndSelectGameObject(string suggestedName, GameObject parent)
  127. {
  128. var parentTransform = parent != null ? parent.transform : null;
  129. var uniqueName = GameObjectUtility.GetUniqueNameForSibling(parentTransform, suggestedName);
  130. var child = new GameObject(uniqueName);
  131. Undo.RegisterCreatedObjectUndo(child, "Create " + uniqueName);
  132. if (parentTransform != null)
  133. Undo.SetTransformParent(child.transform, parentTransform, "Parent " + uniqueName);
  134. Selection.activeGameObject = child;
  135. return child;
  136. }
  137. /// <summary> Checks whether a serialized property has all the bits set when intepreted as a bitmask. </summary>
  138. /// <param name="agentMask"></param>
  139. /// <returns></returns>
  140. static bool IsAll(SerializedProperty agentMask)
  141. {
  142. return agentMask.arraySize == 1 && agentMask.GetArrayElementAtIndex(0).intValue == -1;
  143. }
  144. /// <summary> Marks one agent type as being selected or not. </summary>
  145. /// <param name="userData"></param>
  146. static void ToggleAgentMaskItem(object userData)
  147. {
  148. var args = (object[])userData;
  149. var agentMask = (SerializedProperty)args[0];
  150. var agentTypeID = (int)args[1];
  151. var value = (bool)args[2];
  152. ToggleAgentMaskItem(agentMask, agentTypeID, value);
  153. }
  154. /// <summary> Marks one agent type as being selected or not. </summary>
  155. /// <param name="agentMask"></param>
  156. /// <param name="agentTypeID"></param>
  157. /// <param name="value"></param>
  158. static void ToggleAgentMaskItem(SerializedProperty agentMask, int agentTypeID, bool value)
  159. {
  160. if (agentMask.hasMultipleDifferentValues)
  161. {
  162. agentMask.ClearArray();
  163. agentMask.serializedObject.ApplyModifiedProperties();
  164. }
  165. // Find which index this agent type is in the agentMask array.
  166. int idx = -1;
  167. for (var j = 0; j < agentMask.arraySize; j++)
  168. {
  169. var elem = agentMask.GetArrayElementAtIndex(j);
  170. if (elem.intValue == agentTypeID)
  171. idx = j;
  172. }
  173. // Handle "All" special case.
  174. if (IsAll(agentMask))
  175. {
  176. agentMask.DeleteArrayElementAtIndex(0);
  177. }
  178. // Toggle value.
  179. if (value)
  180. {
  181. if (idx == -1)
  182. {
  183. agentMask.InsertArrayElementAtIndex(agentMask.arraySize);
  184. agentMask.GetArrayElementAtIndex(agentMask.arraySize - 1).intValue = agentTypeID;
  185. }
  186. }
  187. else
  188. {
  189. if (idx != -1)
  190. {
  191. agentMask.DeleteArrayElementAtIndex(idx);
  192. }
  193. }
  194. agentMask.serializedObject.ApplyModifiedProperties();
  195. }
  196. /// <summary> Marks all agent types as not being selected. </summary>
  197. /// <param name="data"></param>
  198. static void SetAgentMaskNone(object data)
  199. {
  200. var agentMask = (SerializedProperty)data;
  201. agentMask.ClearArray();
  202. agentMask.serializedObject.ApplyModifiedProperties();
  203. }
  204. /// <summary> Marks all agent types as being selected. </summary>
  205. /// <param name="data"></param>
  206. static void SetAgentMaskAll(object data)
  207. {
  208. var agentMask = (SerializedProperty)data;
  209. agentMask.ClearArray();
  210. agentMask.InsertArrayElementAtIndex(0);
  211. agentMask.GetArrayElementAtIndex(0).intValue = -1;
  212. agentMask.serializedObject.ApplyModifiedProperties();
  213. }
  214. /// <summary> Obtains one string that represents the current selection of agent types. </summary>
  215. /// <param name="agentMask"></param>
  216. /// <returns> One string that represents the current selection of agent types.</returns>
  217. static string GetAgentMaskLabelName(SerializedProperty agentMask)
  218. {
  219. if (agentMask.arraySize == 0)
  220. return "None";
  221. if (IsAll(agentMask))
  222. return "All";
  223. if (agentMask.arraySize <= 3)
  224. {
  225. var labelName = "";
  226. for (var j = 0; j < agentMask.arraySize; j++)
  227. {
  228. var elem = agentMask.GetArrayElementAtIndex(j);
  229. var settingsName = NavMesh.GetSettingsNameFromID(elem.intValue);
  230. if (string.IsNullOrEmpty(settingsName))
  231. continue;
  232. if (labelName.Length > 0)
  233. labelName += ", ";
  234. labelName += settingsName;
  235. }
  236. return labelName;
  237. }
  238. return "Mixed...";
  239. }
  240. /// <summary> Checks whether a certain agent type is selected. </summary>
  241. /// <param name="agentMask"></param>
  242. /// <param name="agentTypeID"></param>
  243. /// <returns></returns>
  244. static bool AgentMaskHasSelectedAgentTypeID(SerializedProperty agentMask, int agentTypeID)
  245. {
  246. for (var j = 0; j < agentMask.arraySize; j++)
  247. {
  248. var elem = agentMask.GetArrayElementAtIndex(j);
  249. if (elem.intValue == agentTypeID)
  250. return true;
  251. }
  252. return false;
  253. }
  254. }
  255. }