Очень простой метод - снизить скорость при каждом обновлении - концепция, заимствованная из физического сопротивления.
extends KinematicBody2D
var motion = Vector2()
func _physics_process(delta):
if Input.is_action_pressed("ui_right"):
motion.x = 250
elif Input.is_action_pressed("ui_left"):
motion.x = -250
else:
motion.x *= 0.95 # slow down by 5% each frame - play with this value
# i.e. make it dependent on delta to account for different fps
# or slow down faster each frame
# or clamp to zero under a certain threshold
move_and_slide(motion)
pass
Опять же, это очень просто.Настройка значения сопротивления может быть довольно привередливой, если вы хотите дать определенные гарантии (например, игрок должен полностью остановиться после 6 кадров), особенно когда вы имеете дело с разблокированными кадрами в секунду.
В таких случаях вместо этогоиметь один вектор motion
, иметь вектор last_motion
и target_motion
и интерполировать их между собой, чтобы получить текущий вектор motion
в каждом кадре (это можно сделать и для ускорения).Это требует, чтобы вы думали о переходах между состояниями, таких как «когда игрок перестает нажимать на кнопку», стартовых таймерах для отслеживания прогресса между началом и целевым кадром для интерполяции и т. Д. Что за вид функции интерполяции выбор, который вы выберете, будет влиять на восприимчивость или замедление движения игрока.
Вот пример замедления в течение 0,2 секунд с использованием линейной интерполяции:
enum MotionState {IDLE, MOVING, DECELERATING}
extends KinematicBody2D
var state = IDLE
var last_motion = Vector2()
var time_motion = 0.0
func _physics_process(delta):
var motion = Vector2();
if Input.is_action_pressed("ui_right"):
motion.x = 250
state = MOVING
last_motion = motion
elif Input.is_action_pressed("ui_left"):
motion.x = -250
state = MOVING
last_motion = motion
elif state == IDLE
motion.x = 0
else:
if state == MOVING:
# start a smooth transition from MOVING through DECELERATING to IDLE
state = DECELERATING
# last_motion already holds last motion from latest MOVING state
time_motion = 0.2
# accumulate frame times
time_motion -= delta
if time_motion < 0.0:
# reached last frame of DECELERATING, transitioning to IDLE
state = IDLE
motion.x = 0
else:
var t = (0.2 - time_motion) / 0.2 # t goes from 0 to 1
# we're linearly interpolating between last_motion.x and 0 here
motion.x = (1 - t) * last_motion.x
move_and_slide(motion)
pass
Линейное замедление будет ощущаться,но вы можете легко заменить это любой другой функцией, например, попробуйте кубическую для более быстрого замедления и, таким образом, более медленного замедления: motion.x = (1 - (t * t * t)) * last_motion.x