Pooling and Reloading Triggers Teleport

I am using the LocalSpaceRichAI on an NPC that is pooled and reused after death.

When I re-enable the game object after it gets recycled in the pool; The OnEnable in AIBase fires, this calls init, then the Teleport method. The Teleport method moves the transform. But it uses the previous position from when the game object was disabled and also applies the local space offset, which sends the transform far away from where it should be.

I am trying not to modify the base code to fix this. And to be honest, I am not sure how to fix this with the local space offset in play. I suspect the Teleport method isn’t playing nicely in this situation with the local space.

Do you have any thoughts on how to fix this or a good work around?

EDIT: I have a possible workaround I am testing. I save the transform position before enabling the compoent LocalSpaceRichAI, then immediately after, I restore the position on the transform. There doesn’t seem to be a public method to reset LocalSpaceRichAI after I do this. So I am not sure if this will mess anything up with the pathfinding. It seems to be working…
Note: I am using the Ultimate Character Controller, which requires the controller to do all transform moves, otherwise it gets messed up. Moving the transform back and forth like this in the code is safe because UCC doesn’t see the transform was moved.

		/// <summary>Called when the component is enabled</summary>
		protected virtual void OnEnable () {
			FindComponents();
			// Make sure we receive callbacks when paths are calculated
			seeker.pathCallback += OnPathComplete;
			Init();
		}


		void Init () {
			if (startHasRun) {
				// Clamp the agent to the navmesh (which is what the Teleport call will do essentially. Though only some movement scripts require this, like RichAI).
				// The Teleport call will also make sure some variables are properly initialized (like #prevPosition1 and #prevPosition2)
				Teleport(position, false);
				lastRepath = float.NegativeInfinity;
				if (shouldRecalculatePath) SearchPath();
			}
		}

Thanks!
I’ve fixed this locally. In the next beta update the Teleport function will work properly.

1 Like

Hi Aron, Sorry to bug you about this. Do you have an ETA on the next beta that will include this fix. Alternative, would it be possible to PM me the code fix.

My workaround, is working so well :frowning:

Thanks.

Hi

This is the diff for the relevant fix.

commit 259b46794e2968c107da907f90946ffbb6845922
Author: Aron Granberg <aron.granberg@gmail.com>
Date:   Wed Nov 10 20:24:56 2021 +0100

    Fixed the Teleport function not working properly for LocalSpaceRichAI.

diff --git a/Assets/AstarPathfindingProject/Core/AI/RichAI.cs b/Assets/AstarPathfindingProject/Core/AI/RichAI.cs
index f172d831..2c90c90b 100644
--- a/Assets/AstarPathfindingProject/Core/AI/RichAI.cs
+++ b/Assets/AstarPathfindingProject/Core/AI/RichAI.cs
@@ -222,13 +222,16 @@ namespace Pathfinding {
 		 * This ensures that the agent can move to any part of the navmesh.
 		 */
 		public override void Teleport (Vector3 newPosition, bool clearPath = true) {
+			base.Teleport(ClampPositionToGraph(newPosition), clearPath);
+		}
+
+		protected virtual Vector3 ClampPositionToGraph (Vector3 newPosition) {
 			// Clamp the new position to the navmesh
 			var nearest = AstarPath.active != null? AstarPath.active.GetNearest(newPosition) : new NNInfo();
 			float elevation;
 
 			movementPlane.ToPlane(newPosition, out elevation);
-			newPosition = movementPlane.ToWorld(movementPlane.ToPlane(nearest.node != null ? nearest.position : newPosition), elevation);
-			base.Teleport(newPosition, clearPath);
+			return movementPlane.ToWorld(movementPlane.ToPlane(nearest.node != null ? nearest.position : newPosition), elevation);
 		}
 
 		/** Called when the component is disabled */
diff --git a/Assets/AstarPathfindingProject/ExampleScenes/Example13_Moving/LocalSpaceRichAI.cs b/Assets/AstarPathfindingProject/ExampleScenes/Example13_Moving/LocalSpaceRichAI.cs
index ef25c252..263955fd 100644
--- a/Assets/AstarPathfindingProject/ExampleScenes/Example13_Moving/LocalSpaceRichAI.cs
+++ b/Assets/AstarPathfindingProject/ExampleScenes/Example13_Moving/LocalSpaceRichAI.cs
@@ -36,6 +36,17 @@ namespace Pathfinding.Examples {
 		/** Root of the object we are moving on */
 		public LocalSpaceGraph graph;
 
+		protected override Vector3 ClampPositionToGraph (Vector3 newPosition) {
+			RefreshTransform();
+			// Clamp the new position to the navmesh
+			// First we need to transform the position to the same space that the graph is in though.
+			var nearest = AstarPath.active != null? AstarPath.active.GetNearest(graph.transformation.InverseTransform(newPosition)) : new NNInfo();
+			float elevation;
+
+			movementPlane.ToPlane(newPosition, out elevation);
+			return movementPlane.ToWorld(movementPlane.ToPlane(nearest.node != null ? graph.transformation.Transform(nearest.position) : newPosition), elevation);
+		}
+
 		void RefreshTransform () {
 			graph.Refresh();
 			richPath.transform = graph.transformation;
diff --git a/Assets/AstarPathfindingProject/changelog.cs b/Assets/AstarPathfindingProject/changelog.cs
index b3eed546..93efbd07 100644
--- a/Assets/AstarPathfindingProject/changelog.cs
+++ b/Assets/AstarPathfindingProject/changelog.cs
@@ -8,6 +8,7 @@
 	- Fixed some warnings related to ENABLE_UNITY_COLLECTIONS_CHECKS which burst would log when building a standalone player.
 	- Fixed AIPathAlignedToSurface would throw an exception if no RVOController was attached.
 	- Fixed setting \reflink{RichAI.rotation} while the agent was stationary would rotate the agent, but it would immediately rotate back to the previous heading.
+	- Fixed the Teleport function not working properly for \reflink{LocalSpaceRichAI}.
 
 - 4.3.47 (2021-09-04)
 	- Exposed \reflink{AILerp.velocity}.

Wow, that was a quick response :smile:

Thanks very much

Just letting you know, that the code fix worked :smile:

I owe you a beer if I ever run into you!!

1 Like