How do i make the character follow the closest Path2D?

Godot Version

Godot Engine v4.4.1.stable.steam.49a5bc7b6

Question

I am trying to make a mechanic in which the game calculates the closest Path2D and (when the conditions are met) the player follows the closest Path2D. However, i am having difficulties in making the player follow the closest Path2D
My Global Script:

extends Node2D

var RailPositions: Array = []
var closestRail: Node

func _process(delta: float) -> void:
	get_closest_enemy(global_position)
	get_closest_rail(global_position)

func get_closest_rail(pos: Vector2) -> Node2D:
	var distsq = 99999999999999999.0 # "infinity"
	closestRail = null
	for R in RailPositions:
		var testd = pos.distance_squared_to(R.global_position)
		if testd < distsq:
			distsq = testd
			closestRail = R
	return closestRail

My FollowPath2D Script:

extends PathFollow2D

@onready var RemoteTransform = $RailRemoteTransform
@onready var SonicNode = get_node("/root/Node2D/Player")
@onready var RailAimSprite = $"../RailAimSprite"
@onready var RailPath = $".."

func _ready() -> void:
	Global.RailPositions.append(RailPath)
	Global.EnemyPostitions.append(RailAimSprite)


func _process(delta: float) -> void:
	if Global.CanRail:
		Global.GRAVITY = 0
		add_child(RemoteTransform)
		v_offset = 0
		var railSpeed : = 20.0
		progress += railSpeed
		Global.CanHomeAttack = false
		if progress_ratio == 1 or Input.is_action_just_pressed("jump"):
			Global.GRAVITY = 900
			SonicNode.global_rotation = 0
			remove_child(RemoteTransform)
			Global.CanRail = false
			Global.ExitedRail = true
			progress_ratio = 0
		
func _on_can_homeattck_body_entered(body: Node2D) -> void:
	Global.CanHomeAttack = true
	RailAimSprite.show()
	
func _on_can_homeattck_body_exited(body: Node2D) -> void:
	Global.CanHomeAttack = false
	RailAimSprite.hide()
	
func _on_activate_rail_body_entered(body: Node2D) -> void:
	RailAimSprite.hide()
	Global.EnemyPostitions.append(RailAimSprite)
	Global.CanRail = true
	Global.ExitedRail = false

My Remote transform script:

extends RemoteTransform2D
@onready var sonicNode = get_node("/root/Node2D/Player")
func _ready() -> void:
	pass

func _process(delta: float) -> void:
	if Global.CanRail:
		remote_path = sonicNode.get_path()

And my nodes are arranged like this:


What happens when you run it? What error(s) are you seeing?

Okay, so i tried to use the Path2D.curve.get_baked_points(). But i am having problems in making it work in the get_closest_rail function in the Global script

Basically I want it to get the baked points, calculate which one is the closest and make the character follow the Path2D which has the closest point. But I don’t know exactly how to do it…

I understand that.

Typically when reporting a bug or trying to solve a problem you:

  1. Report how made the problem appear.
  2. Report what actually happened (that you didn’t want to happen).
  3. What you expected to happen.

You have successfully communicated #1 and #3. I am asking about #2. Did it give you a null? Did it give you the farthest one instead of the closest? Does it give you one in the middle? Does it give you a random one every time? Does the result change based on where your player is, or do you get the same result every time?

Sorry, i tried to say that the problem now is the error message “invalid access to property ‘global_position’ on a base of type ‘PackedVector2Array’.” I dont know how to get the global positions of the baked points in the Path2D

1 Like

R is a PackedVector2Array. That just means it’s an array that contains Vector2 objects and it’s optimized for searching. You can just put another for loop inside the existing one for each item in the R array and test it.

func get_closest_rail(pos: Vector2) -> Node2D:
	var distsq = 99999999999999999.0 # "infinity"
	closestRail = null
	for R in RailPositions:
		for rail in R:
			var testd = pos.distance_squared_to(rail) # This method takes a Vector2 as an argument.
			if testd < distsq:
				distsq = testd
				closestRail = rail
	return closestRail

I tried it and now it is giving the “Trying to assign value of type ‘Vector2’ to a variable of type ‘Node’.”


How do i transform this vector2 into a node?

Something like:

func get_closest_rail(pos: Vector2) -> Node2D:
	var distsq = 99999999999999999.0 # "infinity"
	closestRail = null
	for R in RailPositions:
		for rail in R:
			var testd = pos.distance_squared_to(rail) # This method takes a Vector2 as an argument.
			if testd < distsq:
				distsq = testd
				var rail_node: Node2D = Node2D.new()
				rail_node.global_position.x = rail.x
				rail_node.global_position.y = rail.y
				closestRail = rail_node
	return closestRail

I think it worked?


(there are only 2 rails in the scene)

1 Like

Looks good! Just keep going with it. If you have an issue in the future, you’ll know what code to come back and investigate. :slightly_smiling_face:

1 Like