Как я могу заставить 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

Другие вопросы по тегам