Custom interpolation For a rhythm game

Godot Version

4.3.stable.mono

Question

some info

I am making a rhythm game that also has a built-in level editor.
I also have made my own custom “Keyframes” to allow better control over how the objects in the level are made.

What am i here to ask?

I need help interpolating between the different keyframes, in the time between the beats, if possible. My goal is to produce the same result on low-end and high-end devices. So preferably i need to interpolate based on a value I calculate(code below)

var bpm : int = 128 # This is set dynamically
var _bps := 60.0 / bpm # Beats per second
var _hbps := _bps * 0.5 # Half beats per second

var time: float = (
	audio_player.get_playback_position()
	+ AudioServer.get_time_since_last_mix()
	- AudioServer.get_output_latency()
)
	
half_beat := int(time / _hbps)

This is my code to calculate half beats, which i then use to control where object is based on my custom keyframes implementation. I need to be able to interpolate different values, which most of them are floats, to the next keyframe smoothly.

My custom Keyframes are just a custom resource, that i put into array and iterate over it.

Custom Keyframe code:

extends Resource
class_name ObjectKeyframe
## Individual Keyframe for object animation

## What Beat does this Keyframe occur on
@export var beat : int

## Position to be at
@export var position : Vector2

## Rotation to be at
@export var rotation : float

## Scale to be at
@export var scale : Vector2

## Opacity to be at, no and no
@export var opacity : float

## To be lerped[br]
## disabled when you want complete manual control
@export var is_lerped : bool = true

Note: is_lerped should be like a control over if it interpolates, just ignore it because my question is asking how to interpolate it…

TLDR; How can i interpolate based on the code i provided, aka.: using the time between beats?

well im new and so proberbly very wrong but cant you just have the stuff you want to be the same on any device run on delta time and things you dont in a normal _process

yeah i can, but not that you say it i wrote the question wrong, its supposed to be how i can interpolate between those two values in the time between the beats that are on my custom keyframes

Ok, so, we need to know:

  • What was the most recent keyframe?
  • What is the next keyframe?
  • How much time does a beat take?
  • How much time has it been since the last beat?

If we know all those things, then it’s just a matter of doing something like:

var position = lerp(
    most_recent_keyframe.position,
    next_keyframe.position,
    time_since_last_beat / time_for_one_beat)

You say you have the keyframes in an array, so I’ll assume you have the first two questions answered, and you have your bpm variable, so that takes care of question 3. For the last one, we can do:

var most_recent_beat_time : int = 0
# We're using milliseconds here, so I will assume that we also
# have time_for_one_beat measured in milliseconds available.
var next_beat_time : int = time_for_one_beat

func _process(_delta):
    var current_time = Time.get_ticks_msec()
    var time_since_last_beat = current_time - most_recent_beat_time
    if current_time >= next_beat_time:
        # Beat! We avoid using the elapsed time here, since
        # that can introduce small inaccuracies. Frames won't
        # necessarily line up perfectly with beats, but we can
        # avoid accumulating error over time.
        most_recent_beat_time = next_beat_time
        next_beat_time += time_for_one_beat

Now, if you use lerp as shown above, you’ll get perfectly linear interpolation. If you want easing, then you’ll need to apply some function to the t parameter - that is, to time_since_last_beat / time_for_one_beat. I recommend taking a look at https://easings.net/ - it’s very much aimed at web, but they do have code examples in typescript, which shouldn’t be too hard to translate to GDScript.

1 Like

Heya!

Thanks for the throughout answer!

Indeed i have every variable i could possibly need for this.
I am sure that i can adapt this code to make it work!

This is exactly what i needed to do, even just linear interpolation is more than enough, as i dont plan to have any fancy effects, just i dont want things jumping around the screen and rather move them there, which this will do more than a good job.

Once again thank you very much!

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.