0 votes

I'm new to Godot and programming in general and have been working on simple 4- Direction Topdown 2D movement. I have gotten the movement to a point I like but have encountered a problem. For the current code certain movement takes priority over another.

For example if I am holding Left and then press Right, the player will move Right, but if I am holding Right and press Left the player will keep moving Right.

I want the player to be able to continue to press a key, then a press a new key and the movement will change to it, but if the second key is released the movement will return to the first.

ie - Holding Up and go Up, but if you press Right you will go Right, then if you release Right, while still holding Up, you will return to going Up.

Im sure this is a simple problem but I've yet to find a solution that works and also keeps 4-Direction movement (I don't want 8 directions).
Anyways here is the code:

extends KinematicBody2D

const TOPDOWN = Vector2(0, 0)
const SPEED = 150

var motion = Vector2()

func _physics_process(delta):
    _controls_loop()
    _movement_loop()    

func _movement_loop():
    motion = move_and_slide(motion, TOPDOWN)

func _controls_loop():
    var right = Input.is_action_pressed("ui_right")
    var left = Input.is_action_pressed("ui_left")
    var up = Input.is_action_pressed("ui_up")
    var down = Input.is_action_pressed("ui_down")

    if right:
        motion.x = SPEED
        motion.y = 0
    elif left:
        motion.x = -SPEED
        motion.y = 0
    elif up:
        motion.x = 0
        motion.y = -SPEED
    elif down:
        motion.x = 0
        motion.y = SPEED
    else:
        motion.x = 0
        motion.y = 0

If anyone could help me or point me in the right direction I would greatly appreciate it

in Engine by (15 points)

1 Answer

+2 votes
Best answer

Not sure if this is the best way, but it seems to work.

extends KinematicBody2D

const TOPDOWN = Vector2(0, 0)
const SPEED = 150

const MOVEMENTS = {
    'ui_up': Vector2.UP,
    'ui_left': Vector2.LEFT,
    'ui_right': Vector2.RIGHT,
    'ui_down': Vector2.DOWN,
}

# hold an ordered list of the currently pressed keys
var direction_history = []
var motion = Vector2()

func _physics_process(delta):
    _controls_loop()
    _movement_loop()

func _movement_loop():
    motion = move_and_slide(motion * SPEED, TOPDOWN)

func _controls_loop():
    # reset motion to zero, so that if no keys are pressed there 
    # will be no movement
    motion = Vector2()

    # loop through all the directions ('ui_up', ui_left', etc),
    # check to see if a key has been released, and if so, we
    # want to remove it from the array holding all the pressed keys
    for direction in MOVEMENTS.keys():
        if Input.is_action_just_released(direction):
            var index = direction_history.find(direction)
            if index != -1:
                direction_history.remove(index)
        if Input.is_action_just_pressed(direction):
            direction_history.append(direction)

    if direction_history.size():
        var direction = direction_history[direction_history.size() - 1]
        motion = MOVEMENTS[direction]
by (1,650 points)
selected by

Thank you! This is working perfectly and I think I understand it. Essentially we are just storing inputs in our array and removing them once they are released, this way the newest input takes priority. I was thinking this was how you had to do it but was not sure how to go about it. Thank you for showing it in a way that makes sense, your comments helped me to understand. :)

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.