NavMeshComponentsGUIUtility.cs 9.4 KB
Newer Older
1 2 3 4 5
using UnityEngine;
using UnityEngine.AI;

namespace UnityEditor.AI
{
6 7 8 9
    public static class NavMeshComponentsGUIUtility
    {
        public static void AreaPopup(string labelName, SerializedProperty areaProperty)
        {
10
            var areaIndex = -1;
11 12 13 14 15 16 17
            var areaNames = GameObjectUtility.GetNavMeshAreaNames();
            for (var i = 0; i < areaNames.Length; i++)
            {
                var areaValue = GameObjectUtility.GetNavMeshAreaFromName(areaNames[i]);
                if (areaValue == areaProperty.intValue)
                    areaIndex = i;
            }
J
Jakob Hunsballe 已提交
18 19
            ArrayUtility.Add(ref areaNames, "");
            ArrayUtility.Add(ref areaNames, "Open Area Settings...");
20 21 22 23 24

            var rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight);
            EditorGUI.BeginProperty(rect, GUIContent.none, areaProperty);

            EditorGUI.BeginChangeCheck();
J
Jakob Hunsballe 已提交
25
            areaIndex = EditorGUI.Popup(rect, labelName, areaIndex, areaNames);
26 27 28 29 30

            if (EditorGUI.EndChangeCheck())
            {
                if (areaIndex >= 0 && areaIndex < areaNames.Length - 2)
                    areaProperty.intValue = GameObjectUtility.GetNavMeshAreaFromName(areaNames[areaIndex]);
J
Jakob Hunsballe 已提交
31 32
                else if (areaIndex == areaNames.Length - 1)
                    NavMeshEditorHelpers.OpenAreaSettings();
33 34 35 36 37 38 39 40 41 42 43 44
            }

            EditorGUI.EndProperty();
        }

        public static void AgentTypePopup(string labelName, SerializedProperty agentTypeID)
        {
            var index = -1;
            var count = NavMesh.GetSettingsCount();
            var agentTypeNames = new string[count + 2];
            for (var i = 0; i < count; i++)
            {
J
Jakob Hunsballe 已提交
45 46
                var id = NavMesh.GetSettingsByIndex(i).agentTypeID;
                var name = NavMesh.GetSettingsNameFromID(id);
47 48 49 50 51
                agentTypeNames[i] = name;
                if (id == agentTypeID.intValue)
                    index = i;
            }
            agentTypeNames[count] = "";
J
Jakob Hunsballe 已提交
52
            agentTypeNames[count + 1] = "Open Agent Settings...";
53 54 55 56

            bool validAgentType = index != -1;
            if (!validAgentType)
            {
J
Jakob Hunsballe 已提交
57
                EditorGUILayout.HelpBox("Agent Type invalid.", MessageType.Warning);
58 59 60 61 62 63
            }

            var rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight);
            EditorGUI.BeginProperty(rect, GUIContent.none, agentTypeID);

            EditorGUI.BeginChangeCheck();
J
Jakob Hunsballe 已提交
64
            index = EditorGUI.Popup(rect, labelName, index, agentTypeNames);
65 66 67 68
            if (EditorGUI.EndChangeCheck())
            {
                if (index >= 0 && index < count)
                {
J
Jakob Hunsballe 已提交
69
                    var id = NavMesh.GetSettingsByIndex(index).agentTypeID;
70 71
                    agentTypeID.intValue = id;
                }
J
Jakob Hunsballe 已提交
72
                else if (index == count + 1)
73
                {
74
                    NavMeshEditorHelpers.OpenAgentSettings(-1);
75 76
                }
            }
77

78 79
            EditorGUI.EndProperty();
        }
80

81
        // Agent mask is a set (internally array/list) of agentTypeIDs.
82 83 84
        // It is used to describe which agents modifiers apply to.
        // There is a special case of "None" which is an empty array.
        // There is a special case of "All" which is an array of length 1, and value of -1.
85 86 87 88
        public static void AgentMaskPopup(string labelName, SerializedProperty agentMask)
        {
            // Contents of the dropdown box.
            string popupContent = "";
89

J
Jakob Hunsballe 已提交
90
            if (agentMask.hasMultipleDifferentValues)
91 92 93 94
                popupContent = "\u2014";
            else
                popupContent = GetAgentMaskLabelName(agentMask);

J
Jakob Hunsballe 已提交
95 96
            var content = new GUIContent(popupContent);
            var popupRect = GUILayoutUtility.GetRect(content, EditorStyles.popup);
97

98
            EditorGUI.BeginProperty(popupRect, GUIContent.none, agentMask);
J
Jakob Hunsballe 已提交
99
            popupRect = EditorGUI.PrefixLabel(popupRect, 0, new GUIContent(labelName));
100 101
            bool pressed = GUI.Button(popupRect, content, EditorStyles.popup);

102 103
            if (pressed)
            {
104 105 106 107 108
                var show = !agentMask.hasMultipleDifferentValues;
                var showNone = show && agentMask.arraySize == 0;
                var showAll = show && IsAll(agentMask);

                var menu = new GenericMenu();
J
Jakob Hunsballe 已提交
109 110 111
                menu.AddItem(new GUIContent("None"), showNone, SetAgentMaskNone, agentMask);
                menu.AddItem(new GUIContent("All"), showAll, SetAgentMaskAll, agentMask);
                menu.AddSeparator("");
112

J
Jakob Hunsballe 已提交
113
                var count = NavMesh.GetSettingsCount();
114 115
                for (var i = 0; i < count; i++)
                {
J
Jakob Hunsballe 已提交
116
                    var id = NavMesh.GetSettingsByIndex(i).agentTypeID;
117
                    var sname = NavMesh.GetSettingsNameFromID(id);
118

J
Jakob Hunsballe 已提交
119
                    var showSelected = show && AgentMaskHasSelectedAgentTypeID(agentMask, id);
120
                    var userData = new object[] { agentMask, id, !showSelected };
J
Jakob Hunsballe 已提交
121
                    menu.AddItem(new GUIContent(sname), showSelected, ToggleAgentMaskItem, userData);
122
                }
123

J
Jakob Hunsballe 已提交
124
                menu.DropDown(popupRect);
125
            }
126 127

            EditorGUI.EndProperty();
128
        }
129

J
Jakob Hunsballe 已提交
130
        public static GameObject CreateAndSelectGameObject(string suggestedName, GameObject parent)
131 132
        {
            var parentTransform = parent != null ? parent.transform : null;
J
Jakob Hunsballe 已提交
133 134
            var uniqueName = GameObjectUtility.GetUniqueNameForSibling(parentTransform, suggestedName);
            var child = new GameObject(uniqueName);
135

J
Jakob Hunsballe 已提交
136
            Undo.RegisterCreatedObjectUndo(child, "Create " + uniqueName);
137
            if (parentTransform != null)
J
Jakob Hunsballe 已提交
138
                Undo.SetTransformParent(child.transform, parentTransform, "Parent " + uniqueName);
139

140
            Selection.activeGameObject = child;
141

142 143
            return child;
        }
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205

        static bool IsAll(SerializedProperty agentMask)
        {
            return agentMask.arraySize == 1 && agentMask.GetArrayElementAtIndex(0).intValue == -1;
        }

        static void ToggleAgentMaskItem(object userData)
        {
            var args = (object[])userData;
            var agentMask = (SerializedProperty)args[0];
            var agentTypeID = (int)args[1];
            var value = (bool)args[2];

            ToggleAgentMaskItem(agentMask, agentTypeID, value);
        }

        static void ToggleAgentMaskItem(SerializedProperty agentMask, int agentTypeID, bool value)
        {
            if (agentMask.hasMultipleDifferentValues)
            {
                agentMask.ClearArray();
                agentMask.serializedObject.ApplyModifiedProperties();
            }

            // Find which index this agent type is in the agentMask array.
            int idx = -1;
            for (var j = 0; j < agentMask.arraySize; j++)
            {
                var elem = agentMask.GetArrayElementAtIndex(j);
                if (elem.intValue == agentTypeID)
                    idx = j;
            }

            // Handle "All" special case.
            if (IsAll(agentMask))
            {
                agentMask.DeleteArrayElementAtIndex(0);
            }

            // Toggle value.
            if (value)
            {
                if (idx == -1)
                {
                    agentMask.InsertArrayElementAtIndex(agentMask.arraySize);
                    agentMask.GetArrayElementAtIndex(agentMask.arraySize - 1).intValue = agentTypeID;
                }
            }
            else
            {
                if (idx != -1)
                {
                    agentMask.DeleteArrayElementAtIndex(idx);
                }
            }

            agentMask.serializedObject.ApplyModifiedProperties();
        }

        static void SetAgentMaskNone(object data)
        {
            var agentMask = (SerializedProperty)data;
206 207
            agentMask.ClearArray();
            agentMask.serializedObject.ApplyModifiedProperties();
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
        }

        static void SetAgentMaskAll(object data)
        {
            var agentMask = (SerializedProperty)data;
            agentMask.ClearArray();
            agentMask.InsertArrayElementAtIndex(0);
            agentMask.GetArrayElementAtIndex(0).intValue = -1;
            agentMask.serializedObject.ApplyModifiedProperties();
        }

        static string GetAgentMaskLabelName(SerializedProperty agentMask)
        {
            if (agentMask.arraySize == 0)
                return "None";

            if (IsAll(agentMask))
                return "All";

            if (agentMask.arraySize <= 3)
            {
                var labelName = "";
                for (var j = 0; j < agentMask.arraySize; j++)
                {
                    var elem = agentMask.GetArrayElementAtIndex(j);
                    var settingsName = NavMesh.GetSettingsNameFromID(elem.intValue);
                    if (string.IsNullOrEmpty(settingsName))
                        continue;

                    if (labelName.Length > 0)
                        labelName += ", ";
                    labelName += settingsName;
                }
                return labelName;
            }

            return "Mixed...";
        }

        static bool AgentMaskHasSelectedAgentTypeID(SerializedProperty agentMask, int agentTypeID)
        {
            for (var j = 0; j < agentMask.arraySize; j++)
            {
                var elem = agentMask.GetArrayElementAtIndex(j);
                if (elem.intValue == agentTypeID)
                    return true;
            }
            return false;
        }
257
    }
258
}