1
\$\begingroup\$

I have added some basic movement and some manual interpolation to a cube that is a kinematic body in Godot.

extends KinematicBody

var speed : int = 10
var slowdown_buffer = 0.2
var movement = Vector3(0,0,0)
func _ready():
    pass
    
func interpolate():
    if movement.x > 0:
            movement.x -= slowdown_buffer
    elif movement.x < 0:
        movement.x += slowdown_buffer
    else:
        movement.x = 0.0
func _physics_process(delta):
    if Input.is_action_pressed("left"):
        movement.x = -speed
    elif Input.is_action_pressed("right"):
        movement.x = speed
    else: 
        interpolate()
        
    move_and_slide(movement)

The problem is that when I move the cube using A and D, after the cube stops after the interpolation, it starts moving in the opposite direction with a non-increasing speed.

How can I fix this?

\$\endgroup\$
1
  • \$\begingroup\$ there's a more simple way to do it, I forgot how, but to learn more go to Coding With tom youtube channel for a simple KinematicBody Movement/meshes/FPS/InvetorySyetem/RayCast Weapon System. (I Also Suggest GarbajYT) \$\endgroup\$ Commented Mar 18, 2021 at 14:15

1 Answer 1

5
\$\begingroup\$

You can't rely on movement.x hitting 0. This is because floating point errors. Instead, check if it is closer to 0 than slowdown_buffer then set it to 0. Like so:

extends KinematicBody

var speed : int = 10
var slowdown_buffer = 0.2
var movement = Vector3(0,0,0)
func _ready():
    pass
    
func interpolate():
    var slowdown = slowdown_buffer
    if movement.x > 0:
        if movement.x < slowdown:
            movement.x = 0
        else:
            movement.x -= slowdown
    elif movement.x < 0:
        if movement.x > -slowdown:
            movement.x = 0
        else:
            movement.x += slowdown

func _physics_process(delta):
    if Input.is_action_pressed("left"):
        movement.x = -speed
    elif Input.is_action_pressed("right"):
        movement.x = speed
    else: 
        interpolate()
        
    move_and_slide(movement)

Another thing I notice is that you are not using delta. And thus your code is not compensating variations in frame rate.

I would pass it to interpolate, and have slowdown = slowdown_buffer * delta. The units of slowdown_buffer were in change of speed per frame, after they are in change of speed per second. Assuming you had a target frame rate of 60, you want to multiply slowdown_buffer by 60, which gives us the value 12.

Like this:

extends KinematicBody

var speed : int = 10
var slowdown_buffer = 12
var movement = Vector3(0,0,0)
func _ready():
    pass
    
func interpolate(delta):
    var slowdown = slowdown_buffer * delta
    if movement.x > 0:
        if movement.x < slowdown:
            movement.x = 0
        else:
            movement.x -= slowdown
    elif movement.x < 0:
        if movement.x > -slowdown:
            movement.x = 0
        else:
            movement.x += slowdown

func _physics_process(delta):
    if Input.is_action_pressed("left"):
        movement.x = -speed
    elif Input.is_action_pressed("right"):
        movement.x = speed
    else: 
        interpolate(delta)
        
    move_and_slide(movement)

However, to better take advantage of the engine, consider using a Tween, for example:

extends KinematicBody

var speed : int = 10
var tween: Tween;
var movement = Vector3(0,0,0);

func _ready():
    tween = Tween.new();
    add_child(tween);

func update_movement(value: float):
    movement.x = value;

func _physics_process(delta):
    if Input.is_action_pressed("left"):
        tween.interpolate_method(self, 'update_movement', -speed, 0, 0.833)
        tween.start()
    elif Input.is_action_pressed("right"):
        tween.interpolate_method(self, 'update_movement', speed, 0, 0.833)
        tween.start()
    
    move_and_slide(movement)

That number 0.833 is the duration. After 0.833 seconds it will reach 0. Originally you were reducing by 0.2 each frame starting from 10, which would take 50 frames. Assuming 60 frames per second, it would take 50/60 seconds to complete, that is aprox 0.833.

Using Tween, you would not have to do these interpolations by hand, nor worry about frames or delta, just set the total time. Furthermore, if you see the documentation for interpolate_method or the other methods in tween, you can see that it allows you to specify a TransitionType and EaseType.

Ah, yes, Tween is a node. It is the little sibling of AnimationPlayer, which you could use to animate any property… Thus, another option is to export movement, create animations in an AnimationPlayer that animate (change over time) movement, and play them.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .