Как я могу заставить 2D-спрайт замедляться до остановки? - PullRequest
0 голосов
/ 04 февраля 2019

Я пытаюсь создать играбельный спрайт в 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 ]

0 голосов
/ 05 февраля 2019

Очень простой метод - снизить скорость при каждом обновлении - концепция, заимствованная из физического сопротивления.

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

0 голосов
/ 05 февраля 2019

Хорошо, я понял это:

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
...