godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.16k stars 21.2k forks source link

Input.set_use_accumulated_input(false) broken? #36664

Open TrickMe opened 4 years ago

TrickMe commented 4 years ago

Godot version: v3.2.stable.official

OS/device including version: Linux Mint Cinnamon 19.3 also tested on: Windows 10 some new build

Issue description: Input is only sent once per frame by _input(event), but i want to use the input in the moment it is triggered, without having to wait to the next frame. So I tried "Input.set_use_accumulated_input(false)", but _input(event) is still called once per frame.

Is this a bug or is set_use_accumulated_input supposed to do something else? There is not much in the documentation about this method.

Steps to reproduce: The minimal project is set to use vsync and count the time in micro-seconds from the start of the last frame to the delivery of the input event. The measurement is displayed at the top lefthand side of the window. The event is set to InputEventMouseButton but can also be changed. Input.set_use_accumulated_input() is set to false. You can set vsync off, but with vsync on it's easier to see, that the time is roughly the same with every mouse-button pressed, instead of evenly distributed from 0 to the frametime in µseconds. If it's the same all the time, that means _input(event) is only called once per frame. On a 60Hz display, vsync enabled, the measured time is, but shouldn't be all the time, about 16667µs.

Minimal reproduction project: inputLatency.zip

SleepProgger commented 4 years ago

Any reason this is closed @TrickMe ?

I am running into a similar problem here. I get multiple mouseevents per frame on linux just fine but on windows this isn't the case. Even when setting Engine.target_fps to 10 i only get 1 event per frame on windows (~13 per frame on linux).

Demo project here: https://share.gnutp.com/godot/TestMouse.zip It counts the mouse movements over a span of 3 seconds.

SleepProgger commented 4 years ago

The problem is that currently the main loop sleeps. This is a problem with windows because this leads to missed messages. I may have a solution for it: https://termbin.com/fybu (os_windows.cpp), but it seems pretty ugly to me. The proper solution would be to not sleep in the message loop ofc, but that would be way more change. If this is a proper approach (i don't think so ;)), let me know and i can send it as PR.

CavemanIke commented 4 years ago

I am running into an issue that I feel may be affected by this. This occurs on both Windows and MacOS. I have a very simple project in which a custom _draw() function is set up on either a Control or Node2D with draw_texture() set to follow the mouse cursor. Be it this method or using a sprite or any other object set to follow the cursor, the object is always lagging 2-3 frames behind resulting in a very sluggish-feeling interface. This can be problematic for games with drag-and-drop style controls. Disabling V-sync helps some, but there is still a small lag and it's not much of a workaround. Setting Input.set_use_accumulated_input() to false does not appear to do anything to help this either.

Calinou commented 4 years ago

@ByteSizeOtter You need to use an hardware mouse cursor to avoid latency. Sending input events as soon as possible won't fix this – Godot 2.x did that, yet the 1-frame latency was still appearant.

You could also extrapolate the drag position to further decrease latency, at the cost of adding some jittering. (If I'm getting it right, linear extrapolation should be relatively easy to achieve by storing the previous position, the current position, and lerp() with a value slightly above 1.)

Disabling V-sync helps some, but there is still a small lag and it's not much of a workaround.

I'm afraid there's nothing we can do about that :slightly_frowning_face: Unfortunately, several platforms enforce V-Sync with no way to disable it.

Calinou commented 3 years ago

The problem is that currently the main loop sleeps. This is a problem with windows because this leads to missed messages. I may have a solution for it: termbin.com/fybu (os_windows.cpp), but it seems pretty ugly to me. The proper solution would be to not sleep in the message loop ofc, but that would be way more change. If this is a proper approach (i don't think so ;)), let me know and i can send it as PR.

@SleepProgger Could you repost your patch here, please? The Termbin link is now 404.

SleepProgger commented 3 years ago

@Calinou I am not working with godot since > a year or so, so no clue if it works but here you go: https://gist.github.com/SleepProgger/0e311421119294f2fb6f24ec751121c7

Its based on 3.2.1-stable. I have no environment set up right now so it might be in a usable state, or it might not. But even if not the idea should still work, if nothing in that area changed in godot (no clue honestly ;))

boltut commented 1 year ago

@Calinou I am sorry, will this bug ever fixed? I use 3.5 version of godot, and just want to draw precise line according to user input, without rendering rate limiting. What is the best way to achieve it on windows? Should I apply patch that was mentioned above or do something else? Thanks!

akien-mga commented 1 year ago

@boltut Did you use Input.set_use_accumulated_input(false)?

This issue is likely fixed in 3.5, there was some confusion in 3.4 on whether input accumulation is enabled or not, but this was fixed in 3.5 (it's enabled by default, can be disabled with that command).

boltut commented 1 year ago

@boltut Did you use Input.set_use_accumulated_input(false)?

This issue is likely fixed in 3.5, there was some confusion in 3.4 on whether input accumulation is enabled or not, but this was fixed in 3.5 (it's enabled by default, can be disabled with that command).

@akien-mga Yes, I try to use it: "Input.set_use_accumulated_input(false)" but it is still doesn't work on windows. And as I understand it is the reason why current issue is still opened.

Calinou commented 1 year ago

and just want to draw precise line according to user input,

To draw lines that are continuous regardless of mouse speed, you need to use Bresenham's line algorithm which can be implemented in GDScript.

boltut commented 1 year ago

and just want to draw precise line according to user input,

To draw lines that are continuous regardless of mouse speed, you need to use Bresenham's line algorithm which can be implemented in GDScript.

@Calinou Thanks for advice, but Bresenham's algorithm doesn't solve problem in my case. I would prefer to use "Input.set_use_accumulated_input(false)" mechanism for my project. It still doesn't work in windows. My question is - can I hope to this bug will be fixed in the nearest future?

Calinou commented 1 year ago

My question is - can I hope to this bug will be fixed in the nearest future?

There is no ETA for resolving issues, as contributors work on a best-effort basis. We don't even know why the issue is occurring in the first place.

As a workaround, you can disable V-Sync while the user is drawing to maximize FPS and reduce input lag. You could also leave V-Sync permanently disabled, but set a FPS limit with Engine.target_fps = ... when the user is not drawing to reduce CPU usage (or enable low processor mode in the project settings).

boltut commented 1 year ago

@Calinou Thanks, got it. But earlier, you had seen patch of @SleepProgger here https://github.com/godotengine/godot/issues/36664#issuecomment-845130116 May be it is possible to embed it to next maintenance release for godot 3.5.x? If it fixes problem.