Kinematic Friction
Problem
You want to add friction and acceleration to your kinematic character, giving it a smoother feel.
Solution
For most games, we’re not necessarily interested in a perfect physics simulation. We want action, responsiveness, and arcade feel. This is why you choose a kinematic body over a rigid one: so that you can control its behavior directly. However, some amount of physics is good - it means an object doesn’t instantly change direction or come to a stop.
Below is the code for a no-frills kinematic platformer character:
extends KinematicBody2D
var speed = 1200
var jump_speed = -1800
var gravity = 4000
var velocity = Vector2.ZERO
func get_input():
velocity.x = 0
if Input.is_action_pressed("ui_right"):
velocity.x += speed
if Input.is_action_pressed("ui_left"):
velocity.x -= speed
func _physics_process(delta):
get_input()
velocity.y += gravity * delta
velocity = move_and_slide(velocity, Vector2.UP)
if Input.is_action_just_pressed("ui_select"):
if is_on_floor():
velocity.y = jump_speed
If you run this code, you’ll see that the character’s x velocity changes instantaneously. To fix this, we’ll use lerp() to gradually increase/decrease the velocity.
Using lerp
lerp(start_value, end_value, amount)
lerp(), aka linear interpolate, finds a “blended” value between two given numbers. See Interpolation for details.
In the code below, friction represents how quickly the character comes to a stop, while acceleration determines how quickly it gets up to full speed. Both are values between 0.0 and 1.0.
Replace the get_input() code with the following:
var friction = 0.1
var acceleration = 0.5
func get_input():
var input_dir = 0
if Input.is_action_pressed("ui_right"):
input_dir += 1
if Input.is_action_pressed("ui_left"):
input_dir -= 1
if dir != 0:
# accelerate when there's input
velocity.x = lerp(velocity.x, dir * speed, acceleration)
else:
# slow down when there's no input
velocity.x = lerp(velocity.x, 0, friction)
Explanation
We’re using friction and acceleration as the amount to blend. For acceleration, we want to find a value between the current speed and the maximum, speed. When decelerating, we’re ramping the current speed down to 0.
Using values of 1.0 would recreate the “instant” movement we started with.
