+1 vote

I need to detect if the mouse has stopped moving in an FPS game.

I'm capturing the cursor by using Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED).

Because of that I have to use event.relative to detect relative mouse movement, like this:

if event is InputEventMouseMotion:
    var mouse_motion = event.relative

However, the mouse_motion variable will never be (0,0), because the value is no longer updated when the mouse stops moving. This is intended behaviour, but doesn't really help.

Is there a way to detect if the mouse has stopped moving? I could use a short timer that resets every time the mouse moves, but that feels like a workaround.

in Engine by (30 points)

3 Answers

+2 votes
Best answer

I assume you want to know if it's stopped moving for some minimal amount of time. In that case, I don't know how you can avoid some sort of time element in the solution.

Whether that's a timer (as you mentioned), or tracking an accumulateddelta in _process, or something else, I think you have to somehow involve time.

Perhaps you could remember the most recent set of mouse coords, and, if they're (reasonably) the same at some point in the future, the mouse hasn't moved. How far into the future, and how you elect to track that time, is up to you I guess...

by (10,914 points)
selected by

maybe the "no time" element he's looking for is just "asap" kinda thing so on the next pass check if it's been updated or the same (same = no movement)

Maybe, but making the check between two consecutive frames is likely too fast, and would not reliably detect what would typically be perceived as a "no motion" state.

Thank you for your answer. The first frame without mouse movement would be desired in my case, but it doesn't have to be that accurate, so a few more frames wil do too. I've settled for the Timer solution.

There's a Timer now with a very short duration of 0.05sec that gets restarted every time the mouse is moved and automatically runs out after the mouse movement has stopped.

+2 votes

Reviving a dead post just in case someone comes across this and wants a better answer.

The trick is to simply reset the mouse_motion variable (or whatever you chose to name it) when you're done using it for that frame.

So using op's code, once you've actually used the mouse_motion variable to move the camera or whatever it is you're using it for

mouse_motion = Vector2.ZERO

That way, if on the next frame there is no mouse movement, mouse_motion will already be equal to zero.

by (28 points)

Can you clarify what you mean by ''reset the variable when you're done using it for that frame"?

Assuming it's called from within _input() (as per the OP's code), where would it fit?

I tried:
input(event): If InputEventMouseMotion: var mousemotion = event.relative function(mouse_motion) mouse motion = Vector2.ZERO

Thanks!

+1 vote

What I did is created a singleton that handles mouse motion and resets the values in the next frame if there was no input.
Put it in AutoLoad and you'll be able to get proper mouse data. The values are also become available from _process() and _physics_process() like

func _process(delta):
    print(str(MouseInput.relative))

I also added mouse wheel scrolls here to be able to get the scrolls state from _process() as well.

extends Node
class_name MouseInput

var relative : Vector2
var scrollFwd : int
var scrollBck : int

var lastFrame : float
var lastMouseMove : float
var lastScrollF : float
var lastScrollB : float

func _process(delta):
    if lastMouseMove < lastFrame:
        relative = Vector2.ZERO

    if lastScrollF < lastFrame:
        scrollFwd = 0;

    if lastScrollB < lastFrame:
        scrollBck = 0

    lastFrame += delta

func _input(event):
    if event is InputEventMouseMotion:
        lastMouseMove = lastFrame
        relative = event.relative
    elif event is InputEventMouseButton:
        if event.button_index == 4:
            lastScrollF = lastFrame
            scrollFwd = 1
        elif event.button_index == 5:
            lastScrollB = lastFrame
            scrollBck = 1
by (16 points)
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.
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 webmaster@godotengine.org with your username.