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.