1
votes

Looking for examples that aren't plagued by the one issue I'm having with this. Everything works fine, inlcuding being able to move in all 8 directions, except:

Input using two directional keys, let's say Up & Down, isn't always simultaneous. In my testing, one of the keys gets registered before the second key 99% of the time. It's a millisecond difference usually, but since I'm doing grid-based movement, this always results in a 4-drectional movement (either U/D/L/R) followed by the intended direction.

I'm not sure if there's an elegant way to hold off moving for 10ms to wait for a second keypress, or to ignore a few inputs and then grab the next one. Any advice would be appreciated.

onready var vLevelGridObjects = get_node_or_null("../../LevelGridObjects")

    var vMoveSpeed = .3
    var vDirection = Vector2(1, 0)
    var vSelf = self
    var vTween = "Player/PlayerTween"
    
    func _process(_delta):
        if Input.is_action_just_released("iPlayerInteract"):
            vLevelGridObjects._ActorInteract(vDirection)
        elif _GetInputDirection() != Vector2(0,0):
            vDirection = _GetInputDirection()
            vLevelGridObjects._ActorMove(vSelf, vTween, vDirection, vMoveSpeed)
    
    func _GetInputDirection():
            return Vector2(Input.get_action_strength("iPlayerRight") - Input.get_action_strength("iPlayerLeft"), Input.get_action_strength("iPlayerDown") - Input.get_action_strength("iPlayerUp"))

----Second attempt----

extends KinematicBody2D

onready var vLevelGridObjects = get_node_or_null("../../LevelGridCollision")

var vMoveSpeed = .25
var vDirection = Vector2(1, 0)
var vReady = 7
var vSelf = self
var vTween = "Player/PlayerTween"

func _process(_delta):
    print(str(vReady))
    if Input.is_action_just_released("iPlayerInteract"):
        vLevelGridObjects._ActorInteract(vDirection)
    elif _GetInputDirection() != Vector2(0,0):
        if vReady == 0:
            vReady = 7
            vDirection = _GetInputDirection()
            vLevelGridObjects._ActorMove(vSelf, vTween, vDirection, vMoveSpeed)
        vReady = vReady - 1

func _GetInputDirection():
        return Vector2(Input.get_action_strength("iPlayerRight") - Input.get_action_strength("iPlayerLeft"), Input.get_action_strength("iPlayerDown") - Input.get_action_strength("iPlayerUp"))
1

1 Answers

1
votes

This is the plan:

  • We are going to keep track of the current time with OS.get_ticks_msec().
  • We will have a time window defined with var max_milliseconds:int = 10.
  • And we will compute the time from which it is ok to start getting input in ok_time.

So, track current time:

func _get_delayed_input_direction() -> Vector2:
    var now:int = OS.get_ticks_msec()
    # ...
    return Vector2.ZERO

Check if there is some ok_time already computed:

var ok_time = null

func _get_delayed_input_direction() -> Vector2:
    var now:int = OS.get_ticks_msec()
    if ok_time == null:
        #...
        pass
    else:
        #...
        pass

    return Vector2.ZERO

If there isn't we need to check if the user just pressed a direction, and if so, we will compute ok_time:

var ok_time = null
var max_milliseconds:int = 10

func _get_delayed_input_direction() -> Vector2:
    var now:int = OS.get_ticks_msec()
    if ok_time == null:
        if _get_direction_just_pressed():
            ok_time = now + max_milliseconds

    else:
        #...
        pass

    return Vector2.ZERO

If there is an ok_time computed, we need to check if there is some input currently. Because if there isn't, we need to erase ok_time:

var ok_time = null
var max_milliseconds:int = 10

func _get_delayed_input_direction() -> Vector2:
    var now:int = OS.get_ticks_msec()
    if ok_time == null:
        if _get_direction_just_pressed():
            ok_time = now + max_milliseconds

    else:
        var found:Vector2 = _get_input_direction()
        if found == Vector2.ZERO:
            ok_time = null
        else:
            # ...
            pass

    return Vector2.ZERO

Of course, if there is some input and we have arrived at ok_time we can return it:

var ok_time = null
var max_milliseconds:int = 10

func _get_delayed_input_direction() -> Vector2:
    var now:int = OS.get_ticks_msec()
    if ok_time == null:
        if _get_direction_just_pressed():
            ok_time = now + max_milliseconds

    else:
        var found:Vector2 = _get_input_direction()
        if found == Vector2.ZERO:
            ok_time = null
        elif now > ok_time:
            return found

    return Vector2.ZERO

And of course, these are the helper functions I was using:

func _get_input_direction() -> Vector2:
    return Vector2(
        Input.get_action_strength("iPlayerRight") - Input.get_action_strength("iPlayerLeft"),
        Input.get_action_strength("iPlayerDown") - Input.get_action_strength("iPlayerUp")
    )

func _get_direction_just_pressed() -> bool:
    return Input.is_action_just_pressed("iPlayerLeft")\
        or Input.is_action_just_pressed("iPlayerRight")\
        or Input.is_action_just_pressed("iPlayerUp")\
        or Input.is_action_just_pressed("iPlayerDown")

Addendum on "second attempt":

When the player presses and releases before vReady reaches 0, its value is not reset. Which means that next time the player presses, vReady will not be counting from its original value. The fix is to set vReady to its default value when the input direction is Vector2.ZERO. By the way, Vector2.ZERO is the same as as Vector2(0,0).

Also, remember that it is counting frames, which timing varies. You might want to set it in time units, and subtract delta instead. And since that could result in negative, you would be checking vReady <= 0. The parameter delta is in seconds, by the way.