[Script Library] Baz Navigation Agent Movement

BazNavAgentMovement

Pathfinding AI movement for GameObjects. Powered by Godot’s built-in NavigationAgent2D so enemies route around walls instead of pushing into them. Six behaviors, one node, no manual state code.

DOWNLOAD:
baz_nav_agent_movement.gd (68.4 KB)

What it does

Pathfinds your enemy to a target using NavigationAgent2D.

  • Patrol — move between waypoints in Loop or Ping-Pong order
  • Chase — pathfind toward an Object, Group, or named node
  • Flee — pathfind away from a threat using probe directions
  • Random Walk — wander within a radius around the start position
  • Set Direction — move at a constant angle, routing around obstacles
  • Move To Point — one-shot trip to a coordinate, object, group, or named node

Behaviors switch mid-game with one call from any visual script state. Speed, acceleration, and deceleration are read from the entity’s existing MoveAndJumpSettings.

Setting up GameObject navigation nodes

  1. Open your enemy’s GameObject (or Area2DGameObject) scene. Add a child Node2D and attach baz_nav_agent_movement.gd to it.

  2. Add a NavigationAgent2D as a sibling of BazNavAgentMovement under the enemy root. Default settings are fine to start.

  3. Select the BazNavAgentMovement node and pick a Behavior Mode from the inspector dropdown. The inspector shows only the fields relevant to the selected mode. Hover any field for a tooltip.

Behavior Mode What it does
Patrol Cycles a waypoint list in Loop or Ping-Pong order
Chase Pathfinds toward the nearest valid target
Flee Pathfinds away from the nearest threat
Random Walk Picks random destinations within a radius of the start position
Set Direction Moves at a constant angle, navigating around obstacles
Move To Point One-shot trip to a coordinate, node, or group member

Using BazNavAgentMovement in your Visual Script

In the enemy’s visual script, pick your AI state and add an InvokeScript Action:

  • Target Node: BazNavAgentMovement
  • Target Method: apply_movement
  • Invoke Timing: OnStateUpdate

That’s the whole runtime wiring. apply_movement() auto-initializes on first call and runs the selected behavior every physics tick.

Setting up GameScene NavigationRegion2D and NavigationPolygon

  1. Open the game scene where the enemy will live. Add a NavigationRegion2D, assign it a NavigationPolygon resource, and draw the walkable area.

  2. Put any TileMapLayer’s or StaticBody2D’s that you want to count as collisions as children of the NavigationRegion2D and press Bake NavigationPolygon in the editor toolbar. Without a baked navmesh the enemy will not move.

  1. If you need to make the path with more radius around corners, you can adjust the Radius property in the NavigationPolygon resource. You will have to rebake it!

Actions

Method When to call
apply_movement() Every physics tick on the active AI state (OnStateUpdate). Required for basic use.
reset_movement() Stops movement and reinitializes on the next apply_movement() call. Only needed for an explicit reset since movement stops on its own when apply_movement() is no longer called.
switch_to_patrol() OnStateEnter of a patrol state. Restarts the waypoint cycle from waypoint 0.
switch_to_chase() OnStateEnter of a chase state. Acquires the nearest valid target.
switch_to_flee() OnStateEnter of a flee state. Acquires the nearest threat.
switch_to_random_walk() OnStateEnter of a wander state.
switch_to_set_direction() OnStateEnter of a fixed-direction state.
switch_to_move_to_point() OnStateEnter of a one-shot move state. Freezes the destination from the configured source.
return_to_start() Pathfinds back to the spawn position.
return_to_nearest_patrol() Pathfinds to the nearest waypoint and resumes patrol from there.

Conditions

For use in visual script transition condition slots (ScriptConditionEvaluator):

Method True when
is_at_destination() Entity has reached its current target
is_moving() Entity has non-zero velocity
has_completed_patrol() A full Loop or Ping-Pong cycle has finished
is_at_start() Entity is back at its spawn position (within 8 px)
is_returning() A return_to_start or return_to_nearest_patrol trip is in progress
is_patrol_paused() Patrol is active and entity is dwelling at a waypoint
is_patrol_at_last_waypoint() Patrol is active and entity is at or heading to the final waypoint
is_chase_has_target() Chase is active and a valid target is locked

Tips

  • Bake the navmesh first. A missing or unbaked NavigationRegion2D is the most common reason nothing moves. Use Debug > Visible Navigation in the editor to confirm the mesh is where you think it is.
  • Speed comes from MoveAndJumpSettings. It will even follow if acceleration is selected.
  • Debug Enabled prints init, target updates, mode switches, and arrival events to Output. Turn it off for release.
  • Switching modes mid-game doesn’t reset speed. The accel/decel ramp carries over between switches. Call reset_movement() first if you want a hard stop.
  • Set Direction uses carrot-on-a-stick pathfinding. It projects a target 128 px ahead and pathfinds to it, so an enemy moving right will still route around walls without permanently deviating.
  • One node per entity. Two BazNavAgentMovement nodes on the same entity will fight over velocity every frame.
6 Likes

I really need this, but I haven’t been able to get it to work. Could you provide a complete working example? Thank you very much!

Welcome to the forums @xinyn!

If things go smoothly, I will be making a video tutorial on how to use it this week. Until then can you share what is not working and maybe I can help?

I made a video for how to use the script and setup navigation regions (at the very top of this thread). Hopefully it is useful!

This video really helped me! My zombie is now moving as intended, thanks so much! If I run into any other issues later on, I’ll be sure to let you know. Thanks again!

1 Like

I’ve run into another issue: the zombies can now patrol or chase according to my settings, but during these actions, they only face one direction and don’t change their facing direction based on their movement direction :sweat_smile:

I’ve tried many things, but I still haven’t been able to solve this problem…

The only thing I can think of would be causing that is:

  1. The animations are not setup for multiple directions
  2. The states you are moving in are not using Movement as the facing type

If you have already tried those and still cannot get it to work, can you send in your project in a zip to pgmmv-support@gotchagotcha.jp so I could investigate why this would be happening?

Thank you for your reply. I have confirmed that the reasons 1 and 2 you mentioned above are not the issue, so it is likely not caused by those settings.

I noticed that in your demo video Navigation Agent Movement - Action Game Maker Godot, you encountered the same problem: the zombies move as set, but their orientation always faces downward instead of facing the direction of movement.

The zombie animations are setup rather lazily on my part. You can see that the idle animation only has 1 direction (downward) so if you are using the idle animation in that state then it will only face down.


Thank you, Baz. My issue is resolved. Thanks for your patient help~

1 Like