+1 vote

Hi all,

I have figured out how to do a press so the event only occurs once. I've learned how to read a keypress event that allows repeated events.

The problem is, it uses my systems typematic delay. So I press the Right Arrow and it moves 1 pixel to the right, then waits a second, then starts moving the rest of the pixels to the right.

How can I get Godot to start and keep moving my sprite whilst the key is down, smoothly, regardless of typematic delays etc?

Thanks a tonne...

asked Feb 2, 2017 in Engine by Robster (808 points)

2 Answers

+1 vote
Best answer

I guess you get this delay because you are using _input, which is an event-based method.
If you want movement at every frame, you need to also use _fixed_process.
So you can create a boolean variable which you set to true when the key is pressed, and false when it's released. Then, in _fixed_process(delta) (which is called every frame), you move whatever you want if the boolean is true.
Or you can also use Input.is_action_pressed("action_name") or Input.is_key_pressed(KEY_*) instead of a boolean, depends on what is better for you :)

Note: _process is also called every frame but it's recommended to do movement and physics in _fixed_process due to it being in sync with the physics engine.

answered Feb 2, 2017 by Zylann (27,004 points)
selected Feb 3, 2017 by Robster

Thank you for the answer. It's a great way to work it out. I've done the following:

func update(delta):
        #let's check for keyboard input on a frame by frame basis
        if(Input.is_key_pressed(KEY_UP)):
            game.direction = -1 #moving up
            move(delta)
        elif(Input.is_key_pressed(KEY_DOWN)):
            game.direction = 1 #moving down
            move(delta)
        else:
            game.direction = 0 #not moving

I'll put this identical response in response to avencherus also as you both gave me what's required. I sort of blended both approaches. You guys are really great. Thanks again

+1 vote

You'll want to poll input in the fixed_processing loop.

extends Node2D
func _ready(): 
    set_fixed_process(true)

func _fixed_process(delta):
    if(Input.is_key_pressed(KEY_UP)): print("key up")
answered Feb 2, 2017 by avencherus (4,831 points)

Thank you for the answer. It's a great way to work it out. I've done the following:

func update(delta):
        #let's check for keyboard input on a frame by frame basis
        if(Input.is_key_pressed(KEY_UP)):
            game.direction = -1 #moving up
            move(delta)
        elif(Input.is_key_pressed(KEY_DOWN)):
            game.direction = 1 #moving down
            move(delta)
        else:
            game.direction = 0 #not moving

I'll put this in response to Zylann also as you both gave me what's required. I sort of blended both approaches.

You may want to stay away from naming the function update if you're using Node2D. They inherit CanvasItem, which has an update() method. It's used to call a canvas redraw.

Well spotted, but it's deliberate.

This function is inside a class and back in the func _ready(): method I have this:

func _fixed_process(delta):
    state.update(delta)

So the idea is, to call the update function within the state class. Very cool thing I learned from the state machine lessons in the flappy bird tutorials. It doesn't matter which state we're in, as we change states this will call the function with the same name in each class that is "state" as per the onready above.

As long as the function in each state is called update then it's fine. Cool huh.

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 How to use this Q&A? before posting your first questions.