Procedural Grid Mover Script not Updating Graph at Runtime

Hello,

I’m currently working on a project that involves a procedurally generated world so I can’t pre-scan the environment.

I’ve had a look at the Procedural example scene and it does help a little bit but the fundamental differences between the example scene and my scene are that…

My scene starts with literally one character object as opposed to the example scene which starts off with the “mine bot” and a ground plane which can be scanned at start and a path generated from that.

My character isn’t exactly controlled by the user input instead it is controlled by the changes the user makes to the environment. So this means, the graph has to be updated very frequently.

My target destination changes every frame.

I’ve tried manually rescanning the graph every second but it isn’t very performant and it’s recently been throwing errors when I try to manually rescan after adding the “Procedural Grid Mover” component.

I’ve read the documentation and it also seems daunting understanding everything at a go. Please, give me an idea of the route to take for me to achieve what I want.

IndexOutOfRangeException: Index was outside the bounds of the array.
Pathfinding.GridNode.GetConnections (System.Action`1[T] action) (at Assets/AstarPathfindingProject/Generators/NodeClasses/GridNode.cs:159)
Pathfinding.HierarchicalGraph.FindHierarchicalNodeChildren (System.Int32 hierarchicalNode, Pathfinding.GraphNode startNode) (at Assets/AstarPathfindingProject/Core/Misc/HierarchicalGraph.cs:304)
Pathfinding.HierarchicalGraph.RecalculateIfNecessary () (at Assets/AstarPathfindingProject/Core/Misc/HierarchicalGraph.cs:236)
Pathfinding.WorkItemProcessor.EnsureValidFloodFill () (at Assets/AstarPathfindingProject/Core/Misc/WorkItemProcessor.cs:231)
Pathfinding.WorkItemProcessor.ProcessWorkItems (System.Boolean force) (at Assets/AstarPathfindingProject/Core/Misc/WorkItemProcessor.cs:324)
AstarPath.PerformBlockingActions (System.Boolean force) (at Assets/AstarPathfindingProject/Core/AstarPath.cs:881)
AstarPath.Update () (at Assets/AstarPathfindingProject/Core/AstarPath.cs:864)
Exception: Processing work items recursively. Please do not wait for other work items to be completed inside work items. If you think this is not caused by any of your scripts, this might be a bug.
Pathfinding.WorkItemProcessor.ProcessWorkItems (System.Boolean force) (at Assets/AstarPathfindingProject/Core/Misc/WorkItemProcessor.cs:265)
AstarPath.PerformBlockingActions (System.Boolean force) (at Assets/AstarPathfindingProject/Core/AstarPath.cs:881)
AstarPath.Update () (at Assets/AstarPathfindingProject/Core/AstarPath.cs:864)
There was an error generating the graphs:
System.NullReferenceException: Object reference not set to an instance of an object
  at Pathfinding.HierarchicalGraph.AddDirtyNode (Pathfinding.GraphNode node) [0x00060] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Core\Misc\HierarchicalGraph.cs:160 
  at Pathfinding.HierarchicalGraph.OnCreatedNode (Pathfinding.GraphNode node) [0x0004c] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Core\Misc\HierarchicalGraph.cs:144 
  at Pathfinding.PathProcessor.InitializeNode (Pathfinding.GraphNode node) [0x00047] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Core\Misc\PathProcessor.cs:259 
  at AstarPath.InitializeNode (Pathfinding.GraphNode node) [0x00001] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Core\AstarPath.cs:1501 
  at Pathfinding.GraphNode..ctor (AstarPath astar) [0x0001d] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Core\Nodes\GraphNode.cs:98 
  at Pathfinding.GridNodeBase..ctor (AstarPath astar) [0x00000] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Generators\NodeClasses\GridNodeBase.cs:7 
  at Pathfinding.GridNode..ctor (AstarPath astar) [0x00000] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Generators\NodeClasses\GridNode.cs:8 
  at Pathfinding.GridGraph+<ScanInternal>d__85.MoveNext () [0x00168] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Generators\GridGenerator.cs:1082 
  at AstarPath+<ScanGraph>d__142.MoveNext () [0x00159] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Core\AstarPath.cs:1796 
  at AstarPath+<ScanAsync>d__141.MoveNext () [0x002f2] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Core\AstarPath.cs:1738 
  at Pathfinding.AstarPathEditor.MenuScan () [0x000e9] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Editor\AstarPathEditor.cs:1430 

If you think this is a bug, please contact me on forum.arongranberg.com (post a new thread)
NullReferenceException: Object reference not set to an instance of an object
Pathfinding.AstarPathEditor.MenuScan () (at Assets/AstarPathfindingProject/Editor/AstarPathEditor.cs:1441)
Pathfinding.AstarPathEditor.DrawSceneGUISettings () (at Assets/AstarPathfindingProject/Editor/AstarPathEditor.cs:719)
Pathfinding.AstarPathEditor.OnSceneGUI () (at Assets/AstarPathfindingProject/Editor/AstarPathEditor.cs:668)
System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at <437ba245d8404784b9fbab9b439ac908>:0)
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at <437ba245d8404784b9fbab9b439ac908>:0)
System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) (at <437ba245d8404784b9fbab9b439ac908>:0)
UnityEditor.SceneView.CallOnSceneGUI () (at <bf679006b1b84db2a5a44842ef13dc36>:0)
UnityEditor.SceneView.HandleSelectionAndOnSceneGUI () (at <bf679006b1b84db2a5a44842ef13dc36>:0)
UnityEditor.SceneView.OnGUI () (at <bf679006b1b84db2a5a44842ef13dc36>:0)
System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at <437ba245d8404784b9fbab9b439ac908>:0)
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at <437ba245d8404784b9fbab9b439ac908>:0)
System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) (at <437ba245d8404784b9fbab9b439ac908>:0)
UnityEditor.HostView.Invoke (System.String methodName, System.Object obj) (at <bf679006b1b84db2a5a44842ef13dc36>:0)
UnityEditor.HostView.Invoke (System.String methodName) (at <bf679006b1b84db2a5a44842ef13dc36>:0)
UnityEditor.HostView.InvokeOnGUI (UnityEngine.Rect onGUIPosition, UnityEngine.Rect viewRect) (at <bf679006b1b84db2a5a44842ef13dc36>:0)
UnityEditor.DockArea.DrawView (UnityEngine.Rect viewRect, UnityEngine.Rect dockAreaRect) (at <bf679006b1b84db2a5a44842ef13dc36>:0)
UnityEditor.DockArea.OldOnGUI () (at <bf679006b1b84db2a5a44842ef13dc36>:0)
UnityEngine.UIElements.IMGUIContainer.DoOnGUI (UnityEngine.Event evt, UnityEngine.Matrix4x4 parentTransform, UnityEngine.Rect clippingRect, System.Boolean isComputingLayout, UnityEngine.Rect layoutSize, System.Action onGUIHandler, System.Boolean canAffectFocus) (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.IMGUIContainer.HandleIMGUIEvent (UnityEngine.Event e, UnityEngine.Matrix4x4 worldTransform, UnityEngine.Rect clippingRect, System.Action onGUIHandler, System.Boolean canAffectFocus) (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.IMGUIContainer.HandleIMGUIEvent (UnityEngine.Event e, System.Action onGUIHandler, System.Boolean canAffectFocus) (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.IMGUIContainer.HandleIMGUIEvent (UnityEngine.Event e, System.Boolean canAffectFocus) (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.IMGUIContainer.SendEventToIMGUI (UnityEngine.UIElements.EventBase evt, System.Boolean canAffectFocus) (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.IMGUIContainer.HandleEvent (UnityEngine.UIElements.EventBase evt) (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.CallbackEventHandler.HandleEventAtTargetPhase (UnityEngine.UIElements.EventBase evt) (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.MouseCaptureDispatchingStrategy.DispatchEvent (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel) (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.EventDispatcher.ApplyDispatchingStrategies (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel, System.Boolean imguiEventIsInitiallyUsed) (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.EventDispatcher.ProcessEvent (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel) (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.EventDispatcher.ProcessEventQueue () (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.EventDispatcher.OpenGate () (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.EventDispatcherGate.Dispose () (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.EventDispatcher.ProcessEvent (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel) (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.EventDispatcher.Dispatch (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel, UnityEngine.UIElements.DispatchMode dispatchMode) (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.BaseVisualElementPanel.SendEvent (UnityEngine.UIElements.EventBase e, UnityEngine.UIElements.DispatchMode dispatchMode) (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.UIElementsUtility.DoDispatch (UnityEngine.UIElements.BaseVisualElementPanel panel) (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.UIElements.UIElementsUtility.ProcessEvent (System.Int32 instanceID, System.IntPtr nativeEventPtr) (at <7be1a95b44f5474c9c1a5c5fd9c86b28>:0)
UnityEngine.GUIUtility.ProcessEvent (System.Int32 instanceID, System.IntPtr nativeEventPtr) (at <35bab3c7b0dc4999845bcfccc7758d96>:0)

There was an error generating the graphs:
System.NullReferenceException: Object reference not set to an instance of an object
  at Pathfinding.GridGraph+<>c.<DestroyAllNodes>b__1_0 (Pathfinding.GraphNode node) [0x00001] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Generators\GridGenerator.cs:102 
  at Pathfinding.GridGraph.GetNodes (System.Action`1[T] action) [0x00014] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Generators\GridGenerator.cs:140 
  at Pathfinding.GridGraph.DestroyAllNodes () [0x00001] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Generators\GridGenerator.cs:97 
  at Pathfinding.NavGraph.Pathfinding.IGraphInternals.DestroyAllNodes () [0x00001] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Generators\Base.cs:379 
  at AstarPath+<ScanAsync>d__141.MoveNext () [0x00182] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Core\AstarPath.cs:1712 
  at Pathfinding.AstarPathEditor.MenuScan () [0x000e9] in C:\Users\User\Documents\Game Project\Infinity Maze\Infinity Maze Base\Assets\AstarPathfindingProject\Editor\AstarPathEditor.cs:1430 

If you think this is a bug, please contact me on forum.arongranberg.com (post a new thread)

UnityEngine.Debug:LogError(Object)
Pathfinding.AstarPathEditor:MenuScan() (at Assets/AstarPathfindingProject/Editor/AstarPathEditor.cs:1439)
Pathfinding.AstarPathEditor:DrawSceneGUISettings() (at Assets/AstarPathfindingProject/Editor/AstarPathEditor.cs:719)
Pathfinding.AstarPathEditor:OnSceneGUI() (at Assets/AstarPathfindingProject/Editor/AstarPathEditor.cs:668)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)

Sure. Could you elaborate a bit on what it is that you want to achieve?

I need a pathfinding solution that constantly searches for a new path in a procedural environment that is also being modified frequently by the player.

I have a constantly moving target which the player character is meant to aim for but never reach it.

The movement of the player character object would be controlled by the AI while the player is costantly changing the game environment witht their input.

I hope this simplifies the problem. I’ll be available to give a better explanation if this isn’t okay enough.

Would the grid need to move like in the procedural example scene?

Otherwise, this is just a case of calling AstarPath.active.UpdateGraphs(bounding box) whenever the player updates the world. See https://arongranberg.com/astar/docs/graph-updates.php#scripting

You can alternatively attach the DynamicGridObstacle component to the colliders which you add/move/whatever. As long as there are not too many of them since then the overhead of checking if they have moved every single frame might become unnecessarily high. Take a look at the Terrain example scene which has two dynamic obstacles with this script.

Using the built-in movement script you can just make sure to assign the ai.destination property every frame (or just use the AIDestinationSetter script and give it a transform which it should follow, this is what is done in the example scenes).

Yeah, the grid would need to move in a similar manner as the procedural example scene.

I’ve tested the “DynamicGridObstacle” already and it doesn’t seem to make a difference as the graph never gets close to one of the objects that the scripts are attached to. I do not plan to use the “DynamicGridObstacle” as there are many objects in my scene that’ll have the script attached to them.

I’ve already implemented the “Target” transform on the AIDestinationSetter component and it seems to work as it should so I don’t have any problems with that.

I’ve tried to implement the AstarPath.active.UpdateGraphs(bounding box) method, however, I still get weird behaviours.

I’ve attached a video that gives a clue on what I’m trying to achieve and the result I get.

Link to Video

Here are the errors I get while calling the Update Graph…

IndexOutOfRangeException: Index was outside the bounds of the array.
Pathfinding.ProceduralGridMover+<UpdateGraphCoroutine>d__12.MoveNext () (at Assets/AstarPathfindingProject/ExampleScenes/Example12_Procedural/ProceduralGridMover.cs:254)
Pathfinding.ProceduralGridMover+<>c__DisplayClass11_0.<UpdateGraph>b__0 (Pathfinding.IWorkItemContext context, System.Boolean force) (at Assets/AstarPathfindingProject/ExampleScenes/Example12_Procedural/ProceduralGridMover.cs:136)
UnityEngine.Debug:LogException(Exception, Object)
Pathfinding.<>c__DisplayClass11_0:<UpdateGraph>b__0(IWorkItemContext, Boolean) (at Assets/AstarPathfindingProject/ExampleScenes/Example12_Procedural/ProceduralGridMover.cs:141)
Pathfinding.WorkItemProcessor:ProcessWorkItems(Boolean) (at Assets/AstarPathfindingProject/Core/Misc/WorkItemProcessor.cs:299)
AstarPath:PerformBlockingActions(Boolean) (at Assets/AstarPathfindingProject/Core/AstarPath.cs:881)
AstarPath:Update() (at Assets/AstarPathfindingProject/Core/AstarPath.cs:864)

IndexOutOfRangeException: Index was outside the bounds of the array.
Pathfinding.GridNode.GetConnections (System.Action`1[T] action) (at Assets/AstarPathfindingProject/Generators/NodeClasses/GridNode.cs:159)
Pathfinding.HierarchicalGraph.FindHierarchicalNodeChildren (System.Int32 hierarchicalNode, Pathfinding.GraphNode startNode) (at Assets/AstarPathfindingProject/Core/Misc/HierarchicalGraph.cs:304)
Pathfinding.HierarchicalGraph.RecalculateIfNecessary () (at Assets/AstarPathfindingProject/Core/Misc/HierarchicalGraph.cs:236)
Pathfinding.WorkItemProcessor.EnsureValidFloodFill () (at Assets/AstarPathfindingProject/Core/Misc/WorkItemProcessor.cs:231)
Pathfinding.WorkItemProcessor.ProcessWorkItems (System.Boolean force) (at Assets/AstarPathfindingProject/Core/Misc/WorkItemProcessor.cs:324)
AstarPath.PerformBlockingActions (System.Boolean force) (at Assets/AstarPathfindingProject/Core/AstarPath.cs:881)
AstarPath.Update () (at Assets/AstarPathfindingProject/Core/AstarPath.cs:864)
Exception: Processing work items recursively. Please do not wait for other work items to be completed inside work items. If you think this is not caused by any of your scripts, this might be a bug.
Pathfinding.WorkItemProcessor.ProcessWorkItems (System.Boolean force) (at Assets/AstarPathfindingProject/Core/Misc/WorkItemProcessor.cs:265)
AstarPath.PerformBlockingActions (System.Boolean force) (at Assets/AstarPathfindingProject/Core/AstarPath.cs:881)
AstarPath.FlushWorkItems () (at Assets/AstarPathfindingProject/Core/AstarPath.cs:1143)
AstarPath.OnDestroy () (at Assets/AstarPathfindingProject/Core/AstarPath.cs:1404)

Hi

If you have such a small graph and it is very grid based it might be easier and faster for you to keep track of all obstacles in e.g. a boolean grid array and then use a ITraversalProvider (https://arongranberg.com/astar/docs/turnbased.html#ITraversalProvider) to set which nodes are obstacles.

If you are keeping track of your obstacles in a grid anyway (which you seem to do) then this should be pretty performant.

I would recommend that you synchronously calculate paths (i.e. call path.BlockUntilCalculated()) to prevent multithreading since the pathfinding algorithms will not like it if you modify the obstacles boolean array at the same time as it is calculating a path.

Hi Aron,

Unfortunately, for a beginner, your asset has been incredibly difficult for me to implement into my project.

Fortunately, I’ve found another asset that’s much easier to implement and does the job as well.

Your asset is still great by the way, but it’s been a pain implementing it for my purpose.

Thanks.

1 Like