0
\$\begingroup\$

I'm trying to add a click to move feature in my game using the new NavigationAgent2D and NavigationPolygonInstance but sometimes when the player reaches the end of the navigation path or changes direction it overshoots the next point so it gets stuck there moving back and forth.

enter image description here

The logic to move the player is pretty straight forward:

Player.tscn

extends KinematicBody2D

export var MAX_SPEED := 250

onready var navigation_agent := $NavigationAgent2D

var velocity := Vector2()

func _ready():
    set_target_location(position)
    
func set_target_location(target: Vector2) -> void:
    navigation_agent.set_target_location(target)

func _physics_process(_delta):
    if navigation_agent.is_navigation_finished():
        return
    
    var move_direction = position.direction_to(navigation_agent.get_next_location())
    velocity = move_direction * MAX_SPEED
    navigation_agent.set_velocity(velocity)

func _on_NavigationAgent2D_velocity_computed(safe_velocity):
    velocity = move_and_slide(safe_velocity)

World.tscn

extends Node2D

onready var player := $Player

func _input(event):
   if event is InputEventMouseButton and event.pressed:
       var target_location = get_global_mouse_position()
       player.set_target_location(target_location)

I tried checking if the player arrived by measuring the distance between its position and the navigation agent next location and forcing it it stop if it gets close. This works if the navigation is a straight line but if it isn't then the player stops as soon as it needs to change direction:

func _physics_process(_delta):
    if navigation_agent.is_navigation_finished() || position.distance_to(navigation_agent.get_next_location()) < 4:
        return

    ...

I created a repo with some minimal code to reproduce the issue, hopefully it can help: https://github.com/jahvi/godot-sample

I think ideally I need to check if my player is within a certain distance from the next point and if so force it to change direction but I'm not sure how to do this.

Can anyone advise how to avoid this overshooting?

\$\endgroup\$
0

1 Answer 1

2
\$\begingroup\$

I've never used Godot, but just searching the API for NavigationAgent2D turns up this:

float path_desired_distance

Default 1.0
Setter set_path_desired_distance(value)
Getter get_path_desired_distance()

The distance threshold before a path point is considered to be reached. This will allow an agent to not have to hit a path point on the path exactly, but in the area. If this value is set [too] high the NavigationAgent will skip points on the path which can lead to leaving the navigation mesh. If this value is set [too] low the NavigationAgent will be stuck in a repath loop cause it will constantly overshoot or undershoot the distance to the next point on each physics frame update.

(Emphasis added - sounds like exactly your problem, right?)

It looks like you're measuring your distances in pixels, and trying to move at 250 pixels per second. At 60 fps that's 4.166 pixels per frame, which means you'll almost never land within the default tolerance range of 1.0. Increase the tolerance to a little over one full time step's worth of movement at your max speed and you should avoid the overshoot.

Do so similarly for target_desired_distance for the end of the path.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks this was exactly it, setting the path_desired_distance and target_desired_distance to ceil(MAX_SPEED / FPS) fixed it. \$\endgroup\$ Sep 6, 2022 at 15:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .