+1 vote

Path2D: How to get index of a closest baked point from described point

Hello everone,

I want to programatically move a player (Kinematic2D) along a path, not from start to end, but starting from a closest point (from player to curve) to end of the path. I refered this article, changed some code & built a test project as shown below: the player moves, but from start to end position.

My test scene:
┖╴root
┖╴Node2D
┠╴Path2D
┖╴KinematicBody2D
┠╴Sprite
┖╴CollisionShape2D

Code:

extends KinematicBody2D

var move_speed = 100
onready var patrol_path = get_node("../Path2D")
var patrol_points
var patrol_index = 0

func _ready():
    get_tree().root.print_tree_pretty()
    patrol_points = patrol_path.curve.get_baked_points()


func _physics_process(delta):
    if patrol_index > patrol_points.size() - 1:
        return

    var target = patrol_points[patrol_index]
    patrol_index += 1
    position = target

Actually what I want is that the player should move to a nearest point on the curve & then move until end. I do not know much about Path2D & related stuff, but what I understood is there are 2 arrays; one for the points that we describe in editor to make the shape of the curve (get_point_count()=55, in my scene) & another is for the points which are baked at 5px (as per the density) interval (get_baked_points().size()=329, in the same scene).

func get_curve_point_index_from_offset(curve, offset):
  var curve_point_length = curve.get_point_count()
  if curve_point_length < 2: return curve_point_length
  for i in range(1, curve.get_point_count()):
      var current_point_offset = curve.get_closest_offset(curve.get_point_position(i))
      if current_point_offset > offset: return i
  return curve_point_length

The above code is from From this post This code returns the index of nearest point in the curve, but that point is from the points which we describe in the editor. Using this code, I changed the code accordingly. I got the required result, but as the number of points in this array are small, the movement is finished very fast, which is not acceptable.

If I can get a point in baked/cached points array a smoother effect can be achieved. So my question is how can I get index of PoolVector2Array array from the index I got in described points.

Thanks!

Godot version 3.3
in Engine by (56 points)

1 Answer

+1 vote
Best answer

I think you can use the interpolate_baked function like this :

#TOTALLY UNTESTED

var offset = 0
var target_point: Vector2
var on_line := false
var speed := 100
func _ready():
    offset = curve.get_closest_offset(global_position)
    target_point = curve.interpolate_baked(offset)

func _physics_process(delta):
    if on_line:
        global_position = curve.interpolate_baked(offset)
        offset += speed * delta
    elif global_position.distance_to(target_point) > DELTA:
        global_position += (target_point - global_position).normalized() * speed
    else:
        on_line = true

P.S. I also think it's better to use function move_and_slide to move the character.

by (90 points)
selected by

Thanks, in the meanwhile, I also watched this tutorial from which I got that using a PathFollow2D it is very easy to move the target along a path: follow.set_offset(follow.get_offset() + 350 * delta)

But again if the sprite is placed at different position other than start point of the curve, the movement misbehaves.

I will test your code suggestion tomorrow & let you know the results. Thanks again!

Thanks.. exactly what I needed.

Though you said that your code was not tested, i worked at the first time like a charm!!! Only I had to define DELTA which I easily figured out.

Really your answer was very helpful to me, thanks a lot again.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.