Как я могу заставить 2D-спрайт замедляться до остановки?
Я пытаюсь создать играбельный спрайт в Godot, используя GDScript. Мой персонаж двигается влево и вправо, а затем останавливается, когда не нажимается ввод.
Однако вместо полной остановки я хочу, чтобы спрайт замедлился. Как бы я это написал?
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
move_and_slide(motion)
pass
2 ответа
Хорошо, я понял это:
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 = motion.x * .9
move_and_slide(motion)
pass
Очень простой метод - снизить скорость при каждом обновлении - концепция, заимствованная из физического сопротивления.
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