Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Input - add get_action_peak_strength() #78176

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

lawnjelly
Copy link
Member

@lawnjelly lawnjelly commented Jun 13, 2023

This PR records the peak strength over each press, which can be read after release, and therefore enables the user to know how hard button was pushed in short presses. This was previously impossible to read after short presses, because strength is reset to zero on release.

Following from #77055 , I'm including this in a separate PR as it deserves separate scrutiny as it is a subtle issue.

Discussion

Although #77055 allows detection of quick action presses and releases (for jump keys etc), there is one situation which it doesn't solve, that is, getting the action strength and raw_strength of these quick presses. The problem is that the existing code sets action_strength and raw_action_strength to ZERO on release. While this works in most situations, with a quick release, it means that if you attempt to find the strength of a button press, the result will be zero, and this information has effectively been lost.

This PR solves the problem by introducing a new function to get the peak strength of an action, which is not reset on release, and can thus be read after a short press (after release).

Storing the peak strength should provide a more reliable measure of how hard the button was pressed, in case several strengths are updated to an action before release.

Notes

  • Again this will require some bikeshedding, there are a number of ways of solving this problem.

@groud
Copy link
Member

groud commented Jun 13, 2023

Thanks for the contribution!

I am not super convinced this should be added. I understand the rationale of allowing to retrieve the strength there, but the first thing I see is the fact it makes the API a bit hard to understand and adds a bit of bloat.

But my main problem with it is: what is it useful for ? When you use is_action_just_pressed(), it means you are trying to detect a transition state from the "not pressed" state to the "pressed" one. Since it's a super short event, I am not sure what the use case would be to retrieve the strength of this less-than-one-frame event. For joysticks, I don't think a less-than-one-frame press makes a lot of sense, and you would use the strength continuously. And for a button, if you use the strength on a press so short it's less than one frame, would it be very relevant for the gameplay ? Like, I don't think any player would be able to precisely choose the strength with which they would push the key for a less-than-one-frame press.

But well, if we want it anyway. I would instead provide two other functions instead of an argument the two get_action_*strength() functions. Something like get_action_just_pressed_strength and get_action_just_pressed_raw_strength. That would be easier to understand and make things more consistent IMO.

@lawnjelly
Copy link
Member Author

lawnjelly commented Jun 13, 2023

Think of it like pressing a jump button, and it registers how hard you've pressed it. Or a fighting game that registers how hard you press punch button or something.

This does depend on whether controllers / APIs we currently support (and OSes) have this feature. If not, it would not be necessary. But I know e.g. music controllers have velocity sensitivity. I know L / R trigger buttons on gamepads support "pressure" (i.e. how far you pull them in usually) but velocity for normal buttons I'm not sure. Pressure for trigger buttons I don't think would be super useful for short presses, so I'd appreciate any feedback for the status with normal buttons.

I did initially add this as two extra functions as you describe, and that would be fine too. Maybe there's an even better way of passing this info (like combining it in a is_action_just_pressed() type function maybe?). 🤔

This is what google bard had to say: 😁

Yes, some game controllers support button press velocity. This means that the game can detect how hard the button is being pressed, and can use this information to control the game. For example, in a racing game, the player could press the gas button harder to go faster.

Here are some game controllers that support button press velocity:

DualShock 2: The DualShock 2 controller was released in 2000 for the PlayStation 2. It has pressure-sensitive face buttons, which means that the game can detect how hard the button is being pressed. This feature was used in some games, such as Gran Turismo 3: A-Spec, to control the acceleration of the car.
Original Xbox controller: The original Xbox controller was released in 2001 for the Xbox console. It also has pressure-sensitive face buttons, which can be used in some games to control the strength of an attack or the speed of a movement.
DualShock 3: The DualShock 3 controller was released in 2006 for the PlayStation 3. It has pressure-sensitive face buttons, like the DualShock 2, but it also has a built-in motion sensor. This allows the game to detect the player's movement, which can be used for things like controlling a character's movement or aiming a weapon.
Steam Deck: The Steam Deck is a handheld gaming PC that was released in 2022. It has pressure-sensitive face buttons, which can be used in some games to control the strength of an attack or the speed of a movement.
It is important to note that not all games support button press velocity. This is because it is a relatively new feature, and not all developers have implemented it in their games. However, it is a growing trend, and more and more games are starting to support it.

Yes, some input APIs support button press velocity. Here are a few examples:

DirectInput: DirectInput is an input API that was developed by Microsoft. It is used by many games to get input from game controllers, keyboards, and mice. DirectInput supports button press velocity, so games can detect how hard the player is pressing a button.
XInput: XInput is a newer input API that was developed by Microsoft. It is used by many games to get input from Xbox controllers. XInput supports button press velocity, so games can detect how hard the player is pressing a button.
Gamepad API: The Gamepad API is a cross-platform input API that is supported by Windows, macOS, and Linux. It supports button press velocity, so games can detect how hard the player is pressing a button.

That's just google bard, I haven't looked at the details of the APIs, how true this is I don't know.

Gamepad API in javascript seems to support this via pressure:

function detectButtonPressure(gamepad, button) {
  if (gamepad) {
    const buttonObject = gamepad.buttons[button];
    if (buttonObject.pressed) {
      console.log("The " + button + " button is pressed.");
      console.log("The amount of pressure being applied is: " + buttonObject.value);
    }
  }
}

const gamepads = navigator.getGamepads();
for (const gamepad of gamepads) {
  detectButtonPressure(gamepad, 0); // A button
  detectButtonPressure(gamepad, 1); // B button
  detectButtonPressure(gamepad, 2); // X button
  detectButtonPressure(gamepad, 3); // Y button
}

It might turn out that doing it via "pressure" is the only way of doing it, as opposed to velocity (which for example MIDI uses). The only question is whether for a quick press we might need to detect "peak pressure", as it might report a lower pressure during the release.

I'll try and find out better whether any APIs support this, and would appreciate any info from those more familiar with the various current input APIs. If it turns out there is no decent API support, I'll close this, but will leave open for a few days to see if we can find out the current situation.

@groud
Copy link
Member

groud commented Jun 13, 2023

Think of it like pressing a jump button, and it registers how hard you've pressed it. Or a fighting game that registers how hard you press punch button or something.

I don't deny that it can be useful to know how hard a button has been pressed. And I think some controllers already provide that. My only concern is about it is in the context of a less-than-one-frame event. I think that, in such a case, it might not be very relevant.

Like, as a dev, if you are interested in the transition from 'not pressed' to 'pressed', I am not sure how relevant would be a strength for such a small amount of time, as users would not really be able to control the pressure anyway. For more than one frame, you can, for example, smooth the strength over several frames to let users control the pressure, but for a single frame, the value might be quite irrelevant IMO.

I did initially add this as two extra functions as you describe, and that would be fine too. Maybe there's an even better way of passing this info (like combining it in a is_action_just_pressed() type function maybe?). thinking

That's an issue with several things in the API. There's no real way to return structs by value. We may be able to return a RefCounted object but that's not really efficient I guess ? (I say that because it's not used often in the API, so TIWAGOS). In the end I guess two new functions would be better and probably more consistent that most of our APIs.

@lawnjelly
Copy link
Member Author

lawnjelly commented Jun 13, 2023

I don't deny that it can be useful to know how hard a button has been pressed. And I think some controllers already provide that. My only concern is about it is in the context of a less-than-one-frame event. I think that, in such a case, it might not be very relevant.

We must consider that not input will be at 60fps. At a low frame rate, or during a slow frame, or at low physics tick rate (e.g. I use 10/15 tps for some games with interpolation) where is_action_just_pressed() is used within physics tick, it is very easy for a short press to be within the frame or tick.

I'm actually coming round to the idea that storing a peak strength per action might be more useful for this, as if a button only supports pressure, it removes the problem of a spurious low pressure input following the max pressure of a press, so I'll change the PR to do this, and add a separate function instead of the extra parameter. Getting a peak strength for an action could also be potentially useful outside of the short press scenario.

That's an issue with several things in the API. There's no real way to return structs by value.

Yup it can be a pain. For a button press actually I don't think there would be a massive need for raw_strength as there is no dead zone.

Maybe a new function get_action_peak_strength() could be the answer? 🤔

I'll try this, but again, depends on whether there is API support. I'll try this out on my gamepad.

UPDATE: PR now updated to have this new get_action_peak_strength() function. I still have to test this on gamepad, but in theory this should do the trick.

@lawnjelly lawnjelly marked this pull request as draft June 13, 2023 12:42
This PR records the peak strength over each press, which can be read after release, and therefore enables the user to know how hard button was pushed in short presses. This was previously impossible to read after short presses, because strength is reset to zero on release.
@lawnjelly lawnjelly changed the title Input - allow retrieval of last pressed action strength Input - add get_action_peak_strength() Jun 13, 2023
@lawnjelly lawnjelly marked this pull request as ready for review June 13, 2023 14:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants