Open madmiraal opened 2 years ago
Question: is there any thought put towards deadzone compensation? e.g. for an axis with a deadzone of 0.15, mapping the input range of 0.15\~1.0 to 0.0\~1.0 as seen by the game. As an option, of course.
Note: As discussed in godotengine/godot#42976 (comment) there is an expectation that the dead zone is circular and not square. There may also be an expectation that each joystick has a different dead zone, although I think this is unlikely.
As I discussed in https://github.com/godotengine/godot-docs/issues/5378, this expectation is not universal, and it shouldn't be Godot's place to play arbiter w/r/t multi-axis deadzone algorithm. Cross-shaped deadzones are sometimes specifically desired. There should be settings for this type of thing.
- Remove Actions's Deadzone and ensure that axes switch pressed from true to false at 0.5. Alternatively, rename it to Trigger.
I'm in favor of renaming it. Some games, like shooters, might want to expose trigger threshold configuration to users on a per-action basis, so that they can set up come actions to be hairtrigger sensitive and others to be fully-depressed insensitive. This is technically an accessibility concern.
- Remove Actions's get_raw_strength() method, as this would no longer be needed.
Even with a properly-functioning deadzone system, this is still something that you might want to use. For example, if you decide to repurpose your "camera tilt" action as a "move virtual mouse cursor" action, you might want to manually program in a different type of deadzone handling for it. You could set up a second action for this particular example, but there are situations where you might want to keep things to one action per physical control.
+1 to cross shaped deadzones sometimes needed.
Question: is there any thought put towards deadzone compensation? e.g. for an axis with a deadzone of 0.15, mapping the input range of 0.15~1.0 to 0.0~1.0 as seen by the game. As an option, of course.
Yes. With a dead zone of 0.15, I think the input range of 0.15-1.0 should linearly increase from 0.0-1.0. There should be no snapping or jumping from 0 to 0.15. Looking at the links in https://github.com/godotengine/godot-docs/issues/5378, the main argument against cross-shaped dead zones is the naïve snapping solution.
I am very concerned and confused by this proposal.
Maybe I have not fully understood this proposal, but it reads to me as if you would propose to completely remove individual deadzones from actions and instead just a one general trigger value for all actions. For joysticks you seem to propose a circular trigger threshold.
If that would be the case it would have a number of problems and deficits compared to the existing deadzone:
Deadzones are set not only by the dev in the project settings but are ideally exposed to the players: Every player has unique controllers with unique wear and tear pattern and therefore needs to be able to set this values for each strength-button and joysick individually. Since deadzones are currently part of the InputMap it's easy to use and save custom profiles for players and their individual hardware (controllers). If you would remove individual per-action Deazone from the Input map, Godot devs would need to write custom code, making this kind of feature harder to implement than it is right now.
Circular deadzone alone would be highly problematic. Axis deadzones need to be the default as it represents player behaviour expectations (being able to move or aim straight). Ideally as Godot devs we should have both for analog joysticks: axis Deadzone plus circular Deadzone and the ability to set/adjust both independently from each other and per action.
@golddotasksquestions The dead zones need to be configurable. The question is: where? The options are:
I think option 2 is the preferred option. Option 1, as you explain, would not allow for changes to be made in game or independently for each axis. Option 3, is the current approach (although it should still be separated from the trigger point), and would allow different dead zones to be set on each half axis, but I don't think this is necessary.
Circular deadzone alone would be highly problematic.
I agree. As you elaborate in godotengine/godot-docs#5378 and @KoBeWi highlights in godotengine/godot#55264, there is an expectation that joystick dead zones are cross-shaped.
I would think deadzones are a requirement for any strength based input, not just analog stick axis. Other than that I think I understood you now and I fully agree with you @madmiraal
I was actually thinking about submitting a proposal on this, but I found this one and I'll weigh in.
Circular deadzone alone would be highly problematic
there is an expectation that joystick dead zones are cross-shaped.
Well, depends on the game or system you're developing. A platformer or top down RPG might expect a cross shaped deadzone, while a twin-stick shooter may require a circular deadzone for accurate aiming controls.
I came across this issue developing a prototype for a platformer. Normal movement necessitates the cross shaped deadzone, however, the player can stop to throw a grapple, which requires a circular deadzone, so some games could require both interchangeably.
It would be easier if the cross-shaped deadzone and circular deadzone were applied at different levels. The circular deadzone would be applied to the joystick before any input mapping, and the cross-shaped deadzone would be applied at the input mapping level.
For example, the deadzone for my current Input.get_axis("player_left", "player_right")
looks like this:
But I could turn on the radial deadzone, which would be applied before the player_left
or player_right
mapping deadzone, then get a deadzone that looks like this:
Then I could dynamically change the deadzone for player_left
and player_right
to 0 during gameplay to get a deadzone that looks like this when the player wants to throw the grapple:
Looking at actual implementation, it would definitely require quite a bit of work as the Input
pump only looks at one axis at a time to make a decision, and it'd have to change to look at two so that it can properly calculate the distance from the middle of the joystick to figure out if it's in the radial deadzone.
Also, if you want to do a radial deadzone, you could insert a radial deadzone check in any _input
function that requires a radial deadzone.
First, you'd create input mappings to your joystick called joy_up
, jown_down
, joy_left
, and joy_right
with no deadzone in the mapping, then you start your _input
or _unhandled_input
function with logic like this:
const RADIAL_DEADZONE = 0.05
func _input(event):
var vaxis = Input.get_axis("joy_up", "joy_down")
var haxis = Input.get_axis("joy_left", "joy_right")
var magnitude = sqrt((vaxis * vaxis) + (haxis * haxis))
if magnitude > RADIAL_DEADZONE:
# Joystick input logic here...
But I can understand how copying and pasting this into every node that handles input can clutter up your codebase, especially if you have to change RADIAL_DEADZONE
on every node. And this also won't override any other mapped input deadzones, so you'll have to change that to 0 as well (or your desired setting) for any other inputs that use the same joystick.
We discussed today this topic during the proposal meeting. We bikeshed a little bit on it but there seem to be no clear consensus. It seems like a quick fix, at least for the deadzone shape, would be to add an optional argument to the Input.get_vector(...)
that would let you define the shape of the deadzone (it would be an enum)
Also, it seems like the current system kind of leads to some sort of confusion. On the one hand, the deadzone is used as a way to filter out garbage events sent by your OS (for joysticks), but on the other hand it is used as a trigger value for boolean (pressed/not pressed) actions.
Having a second look at the original proposal, I personally (this was not discussed in the meeting), think that it is mostly good. I also wonder if, at some point, we should also split "boolean actions" from "analog actions", so that we would only need to assign a trigger value to boolean actions. We would also rework the API so that you could only retrieve the respective type value depending on the action type (pressed status for boolean actions and strength for analog ones). But that's kind of a bigger change, so I am not sure.
So is there any work around for this problem? currently having a PS4 Controller that isn't adhering to deadzone, bought a new controller and tested it too, it's not the controller, it is definitely something to do with the dead zone.
Describe the project you are working on
Any game that uses the joysticks on a joypad.
Describe the problem or limitation you are having in your project
Currently,
InputEvents
can be mapped toActions
via the Project Settings Input Map tab.Actions
have aDeadzone
with a default value of0.5
. ThisDeadZone
affects axes i.e. joysticks, in two ways:Action
's pressed to returntrue
.Action
's strength starts increasing from 0.0 to 1.0, what is commonly understood to be the dead zone.This dual-purpose is a problem. Although it makes sense to have a trigger point of
0.5
for controlling the point at which an axes sets anAction
's pressed totrue
, it doesn't make sense for the dead zone offset.There is a need for a configurable dead zone at the
InputEvent
level. godotengine/godot#43674 highlights that, when a joystick is at rest, there is an expectation that noInputEvents
are sent and that the axis value is0.0
. There have been multiple attempts to address this issue. Initially, godotengine/godot#3101 used a filter that dropped all changes less than 1%. More recently, godotengine/godot#55978 dropped changes less then 5%. The problem with filters is that, as godotengine/godot#42876 highlights, there is also an expectation that the sensitivity of the joystick is not reduced by Godot.Note: To get around the unreasonable value of
0.5
for the dead zone, godotengine/godot#42976 added aget_action_raw_strength()
method, but this removes the dead zone instead of setting it to a reasonable level.Note: Aside from the expectation that a joystick at rest does not send
InputEvents
and that the value is0.0
, the jitter also aggravates the problem described in godotengine/godot#45628 i.e. that when mapping keys and axes to the same action theAction
's pressed is set tofalse
by the axis when just using the keys. This problem is fixed in godotengine/godot#47599.Describe the feature / enhancement and how it helps to overcome the problem or limitation
A new Project Setting for the size of joystick dead zones. This should have a reasonable default value (e.g.
0.05
). Only values greater than this (or less than the negative) are received asInputEventJoypadMotion
events.Note: To avoid confusion, we probably should either rename
Actions
'sDeadzone
toTrigger
or remove it entirely. Would anyone actually want a value other than 0.5 for being the point at which an axis switches anAction
'spressed
fromtrue
tofalse
?Note: As discussed in https://github.com/godotengine/godot/pull/42976#issuecomment-714419377 there is an expectation that the dead zone is circular and not square. There may also be an expectation that each joystick has a different dead zone, although I think this is unlikely.
Note: The main driver for previously putting a filter on the axes appears to be as a workaround to the lack of a functioning dead zone. However, there may still be a need to create another Project Setting for joystick sensitivity, which allows setting the minimum step size of the axis
InputEvent
s.Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
0.05
). Ensure that only values greater than this (or less than the negative) are received asInputEventJoypadMotion
events.Actions
'sDeadzone
and ensure that axes switch pressed fromtrue
tofalse
at 0.5. Alternatively, rename it toTrigger
.Actions
'sget_raw_strength()
method, as this would no longer be needed.InputEventJoypadMotion
events.If this enhancement will not be used often, can it be worked around with a few lines of script?
The changes to the Input Map system cannot be done in a few lines of script. However, a user could ignore the Input Map system and monitor
InputEvent
s themselves checking the axis values and ignoring them if they are less than their required dead zone (or even step size).Furthermore, this feature may not be needed if the only driver for this feature is to address godotengine/godot#45628 i.e. that when mapping keys and axes to the same action the
Action
's pressed is set tofalse
by the axis when just using the keys. However, neither a dead zone nor a filter will properly fix godotengine/godot#45628, because no matter how big the dead zone or filter, there will always be a nudge big enough to set pressed tofalse
. Note: godotengine/godot#45628 is properly fixed in godotengine/godot#47599.However, I believe that separating the current dual-purpose of the
Action
'sDeadzone
into a trigger and a dead zone, and moving the dead zone to theInputEvent
level is an important enhancement.Is there a reason why this should be core and not an add-on in the asset library?
This affects the core Input and Input Map system.