3

So I have my Q and E set to control a Camera that is fixed in 8 directions. The problem is when I call Input.is_action_just_pressed() it sets true two times, so it does its content twice.

This is what it does with the counter:

0 0 0 0 1 1 2 2 2 2

How can I fix thix?

if Input.is_action_just_pressed("camera_right", true):
    if cardinal_count < cardinal_index.size() - 1:
        cardinal_count += 1
    else:
         cardinal_count = 0
    emit_signal("cardinal_count_changed", cardinal_count)
uberflut
  • 120
  • 1
  • 7
  • I tried to reproduce the problem, but it didn't happen for me. Are you running an old version of Godot? On, what operating system are you testing? Also, does this happen with some key in particular? There are a couple similar open issues at the time of writing: https://github.com/godotengine/godot/issues/45443 and https://github.com/godotengine/godot/issues/21550 - If your is one of those cases, you may want to comment there. Otherwise, perhaps open a new issue. Anything that can help narrow down when this happens helps. – Theraot Nov 15 '21 at 23:21
  • Its apparently a little documented thing, they said on godot forums. I'm in 3.4. I used the is_echo() method to fix it and it worked perfectly but now I'm intrigued why that dont happened to you. Its on all keys, may be the keyboard itself? – uberflut Nov 16 '21 at 00:49
  • Well, thinking about it, if you are using `is_echo` it means you are using an `InputEvent`. Are you running your code in `_input`? The method `is_action_just_pressed` is not intended to be used in `_input` but on `_process` or `_physics_process` and it will return true for the whole frame (physics or graphics frame, depending where you call it). So, I didn't test your snipped on `_input`. For `_input` it would be `event.is_action("camera_right") and event.is_pressed() and not event.is_echo()`, I think. – Theraot Nov 16 '21 at 01:06
  • `if event is InputEventKey: if Input.is_action_just_pressed("camera_right", true) and not event.is_echo():` That did it for me. – uberflut Nov 16 '21 at 01:18

3 Answers3

8

On _process or _physics_process

Your code should work correctly - without reporting twice - if it is running in _process or _physics_process.

This is because is_action_just_pressed will return if the action was pressed in the current frame. By default that means graphics frame, but the method actually detect if it is being called in the physics frame or graphic frame, as you can see in its source code. And by design you only get one call of _process per graphics frame, and one call of _physics_process per physics frame.


On _input

However, if you are running the code in _input, remember you will get a call of _input for every input event. And there can be multiple in a single frame. Thus, there can be multiple calls of _input where is_action_just_pressed. That is because they are in the same frame (graphics frame, which is the default).


Now, let us look at the proposed solution (from comments):

if event is InputEventKey:
    if Input.is_action_just_pressed("camera_right", true) and not event.is_echo():
        # whatever
        pass

It is testing if the "camera_right" action was pressed in the current graphics frame. But it could be a different input event that one being currently processed (event).

Thus, you can fool this code. Press the key configured to "camera_right" and something else at the same time (or fast enough to be in the same frame), and the execution will enter there twice. Which is what we are trying to avoid.

To avoid it correctly, you need to check that the current event is the action you are interested in. Which you can do with event.is_action("camera_right"). Now, you have a choice. You can do this:

if event.is_action("camera_right") and event.is_pressed() and not event.is_echo():
    # whatever
    pass

Which is what I would suggest. It checks that it is the correct action, that it is a press (not a release) event, and it is not an echo (which are form keyboard repetition).

Or you could do this:

if event.is_action("camera_right") and Input.is_action_just_pressed("camera_right", true) and not event.is_echo():
    # whatever
    pass

Which I'm not suggesting because: first, it is longer; and second, is_action_just_pressed is really not meant to be used in _input. Since is_action_just_pressed is tied to the concept of a frame. The design of is_action_just_pressed is intended to work with _process or _physics_process, NOT _input.

Theraot
  • 31,890
  • 5
  • 57
  • 86
1

I've encountered the same issue and in my case it was down to the fact that my scene (the one containing the Input.is_action_just_pressed check) was placed in the scene tree, and was also autoloaded, which meant that the input was picked up from both locations and executed twice.

I took it out as an autoload and Input.is_action_just_pressed is now triggered once per input.

Oliver Nicholls
  • 1,342
  • 12
  • 24
0

So, apparently theres a built in method for echo detection: is_echo()

Im closing this.

uberflut
  • 120
  • 1
  • 7