How do I make the party members follow the player?

Godot Version

4.2

Question

I’m making a JRPG-style game where the party members follow the player’s exact route in an equally spaced manner(similar to Earthbound). I’ve tried different approaches like using AStar2D but ultimately settled on a “bread crumbs” solution, where every character (player and party members) pushes its current position to the front of an array (that keeps track of the past 32 positions). Each character also has a reference to the character ahead of it (the target character), looks at that character’s array of positions, and moves to the least recent point if the target character is a defined distance away from it.

Player Code:

extends CharacterBody2D

const speed: int = 100

@onready var _animated_sprite = $AnimatedSprite2D

var input_direction: Vector2
@export var facingState: int
@export var isMoving: bool
@export var pos_trail: Array

enum MovementState {IDLE, LEFT, RIGHT, UP, DOWN}

func get_input():
	input_direction = Input.get_vector("left", "right", "up", "down")
	velocity = input_direction * speed

func _ready():
	#isMoving = false
	pos_trail = [
		position, position, position, position, position, position, position, position, 
		position, position, position, position, position, position, position, position
		] 

func _physics_process(delta):
	get_input()
	move_and_slide()
	if(facingState != MovementState.IDLE):
		pos_trail.push_front(position)
		
	if(pos_trail.size() > 32):
		pos_trail.pop_back()
	
	
	#Animation handling
	if input_direction.x < 0:
		#Going left
		_animated_sprite.play("walk_left")
		facingState = MovementState.LEFT
		#isMoving = true
	elif input_direction.x > 0:
		#Going right
		_animated_sprite.play("walk_right")
		facingState = MovementState.RIGHT
		#isMoving = true
	elif input_direction.y < 0:
		#Going up
		_animated_sprite.play("walk_up")
		facingState = MovementState.UP
		#isMoving = true
	elif input_direction.y > 0:
		#Going down
		_animated_sprite.play("walk_down")
		facingState = MovementState.DOWN
		#isMoving = true
	elif input_direction.x == 0 and input_direction.y == 0:
		#Idle
		match(facingState):
			MovementState.LEFT:
				_animated_sprite.play("idle_left")
			MovementState.RIGHT:
				_animated_sprite.play("idle_right")
			MovementState.UP:
				_animated_sprite.play("idle_up")
			MovementState.DOWN:
				_animated_sprite.play("idle_down")
		
		facingState = MovementState.IDLE

Party NPC Code:

extends CharacterBody2D

@onready var _animated_sprite = $AnimatedSprite2D
@onready var nav_agent: NavigationAgent2D = get_node("NavigationAgent2D")

@export var target_char: CharacterBody2D

@export var facingState: int
@export var followDist: int
@export var pos_trail: Array

const movement_speed: int = 100

enum MovementState {IDLE, LEFT, RIGHT, UP, DOWN}
	
func round_to_dec(num, digit):
	return round(num * pow(10.0, digit)) / pow(10.0, digit)

func _ready():
	#pos_trail = [position, position, position, position, position, position, position, position, position, position, position, position, position, position, position, position]
	pass

func _physics_process(delta):	
	if(facingState != MovementState.IDLE):
		pos_trail.push_front(position)
		
	if(pos_trail.size() > 32):
		pos_trail.pop_back()
		
	var direction: Vector2
		
	if(target_char.pos_trail.size() > 0 and target_char.position.distance_to(target_char.pos_trail.back()) > followDist):
		#print(target_char.pos_trail.back())
		while(round_to_dec(target_char.position.distance_to(position), 0) <= round_to_dec(target_char.position.distance_to(target_char.pos_trail.back()), 0) and facingState != MovementState.IDLE):
			#print("Moving away from player")
			target_char.pos_trail.pop_back()
		direction = target_char.pos_trail.back() - position
		#print(direction)
		position = position.move_toward(target_char.pos_trail.pop_back(), delta * movement_speed)
	else:
		#print("IDLE")
		direction =  Vector2(0, 0)
	
	#Animation handling
	#var hor_anim_snap = 25
	#var vert_anim_snap = 1
	if round_to_dec(direction.x, 1) < 0:
		#Going left
		_animated_sprite.play("walk_left")
		facingState = MovementState.LEFT
	elif round_to_dec(direction.x, 1) > 0:
		#Going right
		_animated_sprite.play("walk_right")
		facingState = MovementState.RIGHT
	elif direction.y < 0:
		#Going up
		_animated_sprite.play("walk_up")
		facingState = MovementState.UP
	elif direction.y > 0:
		#Going down
		_animated_sprite.play("walk_down")
		facingState = MovementState.DOWN
	elif direction.x == 0 and direction.y == 0:
		#Idle
		match(facingState):
			MovementState.LEFT:
				_animated_sprite.play("idle_left")
			MovementState.RIGHT:
				_animated_sprite.play("idle_right")
			MovementState.UP:
				_animated_sprite.play("idle_up")
			MovementState.DOWN:
				_animated_sprite.play("idle_down")
		
		facingState = MovementState.IDLE

With this code, the party NPCs do in fact follow the player’s exact path but spacing between the characters is not constant. What are ways that I could fix this?

Any feedback is welcome and appreciated. Thanks!