Smooth bezier_interpolate concatenation

Godot Version

4.6

Question

Heyya!

So, as the title says, I want to make a smooth concatenation of curves by using bezier_interpolate.

I’m making a 2D game in which there are stars flying throughout the screen in a curved-like movement. These curves are made by passing random coordinates as values to bezier_interpolate (they don’t need to be random, I might end up changing it, but that isn’t relevant now). Whenever a curve is finished, new random values are calculated and passed to bezier_interpolate to call it again. In this process, the point where the last curve finished is used as the start point of the next one. The problem with all of this is that there’s no curve between one bezier_interpolate and another one. When a curve finishes, the star makes an abrupt change in the direction to start the next one, and even the velocity changes (I’d like to attach a video, but a cannot given I’m a new user).

I don’t need the star to follow the same direction all the time (which, by the way, I’ve already tried), I need the transition between curves to be smoother.

Here’s my last code:

extends Node2D

var start: Vector2
var control1: Vector2
var control2: Vector2
var end: Vector2
var t := 0.0


func _ready() -> void:
	global_position = Vector2(randf_range(0, 1152), randf_range(0, 648))

    #Calculates the first values for the curve.
	_generate_new_curve(global_position)

func _process(delta: float) -> void:
	t += delta / duration

    #Determines if a curve is finished. If so, prepares new values.
    if t >= 1.0:
		_generate_new_curve(end)

	global_position = start.bezier_interpolate(control1, control2, end, t)

func _generate_new_curve(from: Vector2):
	start = from
	end = Vector2(randf_range(0, 1152), randf_range(0, 648))
	control1 = Vector2(randf_range(0, 1152), randf_range(0, 648))
	control2 = Vector2(randf_range(0, 1152), randf_range(0, 648))

	t = 0.0

I’ve spent much time on this, looked for solutions and tried new things, and even tried to replicate bezier_interpolate by manually coding the curves (didn’t work (well the curve did, but the problem persisted)). So, I don’t know what else I can do but write here. I began to code within a month ago, so I’m pretty new in this.

I cannot think what other information could be useful for you, because that’s pretty much all I have. Thank you in advance!

Well, you’re only ensuring the positional continuity by making the start point of the next curve coincident with the end point of the previous curve. On top of that you need to ensure the tangential continuity by putting the first control point of the next curve onto the line formed by the second control point and the endpoint of the previous curve.

Thanks for the reply. Also, may I ask how can I do it? I cannot think how to.

Also note that bezier curve parametrization is not uniform. If you increase t linearly in real time, your apparent velocity won’t be constant if you use bezier interpolation.

If you need object to move at constant velocity - using bezier interpolation might not be the best option. What exact motion are you trying to achieve?

A constant, non-stop movement based on long curves and random destinations.

A better approach might be to move along circular arcs or just steer the velocity direction by a small angle per frame.

You can also try using PathFollow2D instead, which will uniformly reparametrize the curve you supply, ensuring the constant velocity.

If you insist on using beziers directly, Vector2::bezier_interpolate() won’t be sufficient. You’ll have to build bezier segments using Curve2D which provides facilities to uniformly sample the tessellated curve.

I’ll take a look to it. Thanks for your help.