How do I get a node using Navigation2D to follow a moving KinematicBody2D?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By ianzzap

I have been following this tutorial on how to use Navigation2D because it seems to be exactly what I need, due to the updating path function. In my game, the position that the nodes are moving toward is the player.
Problem
My Enemy node navigates and moves around walls but only moves toward the position where the Player started. I have tried using the pos_update signal to update the path, but that isn’t working. It would be very appreciated if someone would help me or introduce me to new methods. (calling update_path() on process() doesn’t work)
Main scene code

extends Node2D

signal pos_update

var enem = preload("res://Enemy.tscn")
onready var pos1 = $Position2D.position
onready var pos2 = $Position2D2.position
onready var pos3 = $Position2D3.position
onready var navv = $Navigation2D
onready var end_pos = $Player/Position2D.position



# Called when the node enters the scene tree for the first time.
func _ready():
	pass



# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
#	pass


func _on_Timer_timeout():
	var e = enem.instance()
	add_child(e)
	e.position = pos1
	e.goal = end_pos
	e.nav = navv
	connect("pos_update", e,"update_path")

func _on_Timer2_timeout():
	var e = enem.instance()
	add_child(e)
	e.position = pos2
	e.goal = end_pos
	e.nav = navv
	connect("pos_update", e,"update_path")


func _on_Timer3_timeout():
	var e = enem.instance()
	add_child(e)
	e.position = pos3
	e.goal = end_pos
	e.nav = navv
	connect("pos_update", e,"update_path")

Enemy code

extends KinematicBody2D


const GRAVITY = 950
const WALK_SPEED = 400
onready var player = get_parent().get_node("Player")
var velocity = Vector2()

var DIRECTION_RIGHT = 1
var DIRECTION_LEFT = -1
var direction = Vector2(DIRECTION_RIGHT, 1)
var react_time = 400
var dir = 0
var next_dir_time = 0
var next_dir = 0
var next_dir_y = 0
var next_dir_time_y = 0
var dir_y = 0
var helth = 6
var cn = true


var nav = null setget set_nav
var path = []
var goal = Vector2()

func _ready():
	pass

func set_nav(new_nav):
	nav = new_nav
	update_path()

func update_path():
	path = nav.get_simple_path(position, goal, false)


func _process(delta):
	if path.size() > 1:
		var d = position.distance_to(path[0])
		if d > 2:
			position = position.linear_interpolate(path[0], (WALK_SPEED * delta)/d)
		else:
			path.remove(0)

call “update_path()” on _process()

extends KinematicBody2D


const GRAVITY = 950
const WALK_SPEED = 400
onready var player = get_parent().get_node("Player")
var velocity = Vector2()

var DIRECTION_RIGHT = 1
var DIRECTION_LEFT = -1
var direction = Vector2(DIRECTION_RIGHT, 1)
var react_time = 400
var dir = 0
var next_dir_time = 0
var next_dir = 0
var next_dir_y = 0
var next_dir_time_y = 0
var dir_y = 0
var helth = 6
var cn = true


var nav = null setget set_nav
var path = []
var goal = Vector2()

func _ready():
    pass

func set_nav(new_nav):
    nav = new_nav
    update_path()

func update_path():
    path = nav.get_simple_path(position, goal, false)


func _process(delta):
    update_path():
    if path.size() > 1:
        var d = position.distance_to(path[0])
        if d > 2:
            position = position.linear_interpolate(path[0], (WALK_SPEED * delta)/d)
        else:
            path.remove(0)

dustin | 2020-06-23 05:08

I have already tried this. The enemy just spawns and doesn’t move.

ianzzap | 2020-06-23 06:23

oh. i guess i tried :confused:

dustin | 2020-06-23 06:44

:bust_in_silhouette: Reply From: Kanor

I’ve done something similar for a sentry enemy that chases players that it sees. From what I can see, the main problem is that the enemies aren’t keeping track of the player.

onready var end_pos = $Player/Position2D.position

Instead you should do:

onready var player = $Player/Position2D

...

func _on_Timer2_timeout():
    var e = enem.instance()
    add_child(e)
    e.position = pos2
    e.kinematic_goal = player
    e.nav = navv
    connect("pos_update", e,"update_path")

And then in the enemy:

func update_path():
    path = nav.get_simple_path(position, kinematic_goal.position, false) # Note use of kinematic_goal node to get up-to-date position of player

func _process(delta):
    if path.size() > 1:
        var d = position.distance_to(path[0])
    if d > 2:
        position = position.linear_interpolate(path[0], (WALK_SPEED * delta)/d)
    else:
        path.remove(0)
        update_path() # IMPORTANT BIT

Technically, you could just call update_path() only when path.size == 0, but I’ve found that it makes the enemies feel more responsive when they recalculate their direction more consistently (you could also add a counter to update_path every couple of frames).