diff options
Diffstat (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Editor/AIBaseEditor.cs')
-rw-r--r-- | Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Editor/AIBaseEditor.cs | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Editor/AIBaseEditor.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Editor/AIBaseEditor.cs new file mode 100644 index 0000000..ce8e318 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Editor/AIBaseEditor.cs @@ -0,0 +1,188 @@ +using UnityEditor; +using UnityEngine; + +namespace Pathfinding { + [CustomEditor(typeof(AIBase), true)] + [CanEditMultipleObjects] + public class BaseAIEditor : EditorBase { + float lastSeenCustomGravity = float.NegativeInfinity; + bool debug = false; + + protected void AutoRepathInspector () { + var mode = FindProperty("autoRepath.mode"); + + PropertyField(mode, "Recalculate paths automatically"); + if (!mode.hasMultipleDifferentValues) { + var modeValue = (AutoRepathPolicy.Mode)mode.enumValueIndex; + EditorGUI.indentLevel++; + if (modeValue == AutoRepathPolicy.Mode.EveryNSeconds) { + FloatField("autoRepath.period", min: 0f); + } else if (modeValue == AutoRepathPolicy.Mode.Dynamic) { + var maxInterval = FindProperty("autoRepath.maximumPeriod"); + FloatField(maxInterval, min: 0f); + Slider("autoRepath.sensitivity", 1.0f, 20.0f); + if (PropertyField("autoRepath.visualizeSensitivity")) { + EditorGUILayout.HelpBox("When the game is running the sensitivity will be visualized as a magenta circle. The path will be recalculated immediately if the destination is outside the circle and more quickly if it is close to the edge.", MessageType.None); + } + EditorGUILayout.HelpBox("The path will be recalculated at least every " + maxInterval.floatValue.ToString("0.0") + " seconds, but more often if the destination changes quickly", MessageType.None); + } + EditorGUI.indentLevel--; + } + } + + protected void DebugInspector () { + debug = EditorGUILayout.Foldout(debug, "Debug info"); + if (debug) { + var ai = target as IAstarAI; + EditorGUI.BeginDisabledGroup(true); + EditorGUILayout.Toggle("Reached Destination", ai.reachedDestination); + EditorGUILayout.Toggle("Reached End Of Path", ai.reachedEndOfPath); + if (ai is AIBase aiBase && aiBase.rvoDensityBehavior.enabled) { + EditorGUILayout.Toggle("Destination is crowded", aiBase.rvoDensityBehavior.lastJobDensityResult); + } + EditorGUILayout.Toggle("Path Pending", ai.pathPending); + EditorGUILayout.Vector3Field("Destination", ai.destination); + EditorGUILayout.LabelField("Remaining distance", ai.remainingDistance.ToString("0.00")); + EditorGUI.EndDisabledGroup(); + } + } + + protected override void Inspector () { + var isAIPath = typeof(AIPath).IsAssignableFrom(target.GetType()); + + Section("Shape"); + FloatField("radius", min: 0.01f); + FloatField("height", min: 0.01f); + + Section("Pathfinding"); + AutoRepathInspector(); + + Section("Movement"); + + PropertyField("canMove"); + FloatField("maxSpeed", min: 0f); + + if (isAIPath) { + EditorGUI.BeginChangeCheck(); + var acceleration = FindProperty("maxAcceleration"); + int acc = acceleration.hasMultipleDifferentValues ? -1 : (acceleration.floatValue >= 0 ? 1 : 0); + var nacc = EditorGUILayout.Popup("Max Acceleration", acc, new [] { "Default", "Custom" }); + if (EditorGUI.EndChangeCheck()) { + if (nacc == 0) acceleration.floatValue = -2.5f; + else if (acceleration.floatValue < 0) acceleration.floatValue = 10; + } + + if (!acceleration.hasMultipleDifferentValues && nacc == 1) { + EditorGUI.indentLevel++; + PropertyField(acceleration.propertyPath); + EditorGUI.indentLevel--; + acceleration.floatValue = Mathf.Max(acceleration.floatValue, 0.01f); + } + + Popup("orientation", new [] { new GUIContent("ZAxisForward (for 3D games)"), new GUIContent("YAxisForward (for 2D games)") }); + } else { + FloatField("acceleration", min: 0f); + + // The RichAI script doesn't really support any orientation other than Z axis forward, so don't expose it in the inspector + FindProperty("orientation").enumValueIndex = (int)OrientationMode.ZAxisForward; + } + + if (PropertyField("enableRotation")) { + EditorGUI.indentLevel++; + FloatField("rotationSpeed", min: 0f); + if (PropertyField("slowWhenNotFacingTarget")) { + EditorGUI.indentLevel++; + PropertyField("preventMovingBackwards"); + EditorGUI.indentLevel--; + } + EditorGUI.indentLevel--; + } + + if (isAIPath) { + FloatField("pickNextWaypointDist", min: 0f); + FloatField("slowdownDistance", min: 0f); + } else { + FloatField("slowdownTime", min: 0f); + FloatField("wallForce", min: 0f); + FloatField("wallDist", min: 0f); + PropertyField("funnelSimplification"); + } + + FloatField("endReachedDistance", min: 0f); + PropertyField("whenCloseToDestination"); + + if (isAIPath) { + PropertyField("alwaysDrawGizmos"); + PropertyField("constrainInsideGraph"); + } + + var mono = target as MonoBehaviour; + mono.TryGetComponent<Pathfinding.RVO.RVOController>(out Pathfinding.RVO.RVOController rvoController); + if (rvoController && rvoController.enabled) { + if (PropertyField("rvoDensityBehavior.enabled", "Stop when destination is crowded")) { + EditorGUI.indentLevel++; + PropertyField("rvoDensityBehavior.densityThreshold"); + PropertyField("rvoDensityBehavior.returnAfterBeingPushedAway"); + EditorGUI.indentLevel--; + } + } else { + EditorGUI.BeginDisabledGroup(true); + EditorGUILayout.Toggle(new GUIContent("Stop when destination is crowded", "Requires an attached RVOController"), false); + EditorGUI.EndDisabledGroup(); + } + + mono.TryGetComponent<Rigidbody>(out Rigidbody rigid); + mono.TryGetComponent<Rigidbody2D>(out Rigidbody2D rigid2D); + mono.TryGetComponent<CharacterController>(out CharacterController controller); + var canUseGravity = (controller != null && controller.enabled) || ((rigid == null || rigid.isKinematic) && (rigid2D == null || rigid2D.isKinematic)); + + var gravity = FindProperty("gravity"); + var groundMask = FindProperty("groundMask"); + + if (canUseGravity) { + EditorGUI.BeginChangeCheck(); + int grav = gravity.hasMultipleDifferentValues ? -1 : (gravity.vector3Value == Vector3.zero ? 0 : (float.IsNaN(gravity.vector3Value.x) ? 1 : 2)); + var ngrav = EditorGUILayout.Popup("Gravity", grav, new [] { "None", "Use Project Settings", "Custom" }); + if (EditorGUI.EndChangeCheck()) { + if (ngrav == 0) gravity.vector3Value = Vector3.zero; + else if (ngrav == 1) gravity.vector3Value = new Vector3(float.NaN, float.NaN, float.NaN); + else if (float.IsNaN(gravity.vector3Value.x) || gravity.vector3Value == Vector3.zero) gravity.vector3Value = Physics.gravity; + lastSeenCustomGravity = float.NegativeInfinity; + } + + if (!gravity.hasMultipleDifferentValues) { + // A sort of delayed Vector3 field (to prevent the field from dissappearing if you happen to enter zeroes into x, y and z for a short time) + // Note: cannot use != in this case because that will not give the correct result in case of NaNs + if (!(gravity.vector3Value == Vector3.zero)) lastSeenCustomGravity = Time.realtimeSinceStartup; + if (Time.realtimeSinceStartup - lastSeenCustomGravity < 2f) { + EditorGUI.indentLevel++; + if (!float.IsNaN(gravity.vector3Value.x)) { + PropertyField(gravity.propertyPath); + } + + if (controller == null || !controller.enabled) { + PropertyField(groundMask.propertyPath, "Raycast Ground Mask"); + } + + EditorGUI.indentLevel--; + } + } + } else { + EditorGUI.BeginDisabledGroup(true); + EditorGUILayout.Popup(new GUIContent(gravity.displayName, "Disabled because a non-kinematic rigidbody is attached"), 0, new [] { new GUIContent("Handled by Rigidbody") }); + EditorGUI.EndDisabledGroup(); + } + + DebugInspector(); + + if ((rigid != null || rigid2D != null) && (controller != null && controller.enabled)) { + EditorGUILayout.HelpBox("You are using both a Rigidbody and a Character Controller. Those components are not really designed for that. Please use only one of them.", MessageType.Warning); + } + + var isRichAI = typeof(RichAI).IsAssignableFrom(target.GetType()); + if (isRichAI && Application.isPlaying && AstarPath.active != null && AstarPath.active.graphs.Length > 0 && AstarPath.active.data.recastGraph == null && AstarPath.active.data.navmesh == null) { + EditorGUILayout.HelpBox("This script only works with a navmesh or recast graph. If you are using some other graph type you might want to use another movement script.", MessageType.Warning); + } + } + } +} |