summaryrefslogtreecommitdiff
path: root/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Editor/AIBaseEditor.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Editor/AIBaseEditor.cs')
-rw-r--r--Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Editor/AIBaseEditor.cs188
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);
+ }
+ }
+ }
+}