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

Fix joystick movement thresholds and run behavior #51

Closed
wants to merge 4 commits into from

Conversation

Macil
Copy link
Contributor

@Macil Macil commented Mar 5, 2023

I've been playing a lot of both Quakespasm(/vkQuake) and the Kex port with a controller. Compared to Kex, I've noticed that fine movement control seems harder, and the always-run setting and the run key barely impact your speed when the joystick is held all the way. I decided to investigate the joystick handling code, and I fixed a few smoking gun issues that were holding things back.

  1. Fixed the issue where holding the movement joystick at a 45 degree angle would make you move at a different angle instead (41 degrees if you have always-run set to "Vanilla", otherwise 60 degrees!). (Yes, this is the same as what happens if you hold the forward and left/right keyboard keys, but it's a bit disorienting when using a joystick where you're supposed to be able to feel the angle and have finer control over it.) Now you move at the same angle as the joystick, just like with the Kex port and most games.
  2. Fixed the issue where holding the movement joystick all the way while not running would make you move at speed 283 instead of 200. This made it very hard to notice the difference between running and walking with a controller. This fix seems to also be consistent with the Kex port.
  3. Fixed the issue where when running you reach the maximum speed while holding the joystick at only 83% (when joy_exponent_move is at its default value of 3, and when joy_exponent_move is 2, 75%, and when joy_exponent_move is 1, 57%). The joystick maxing out so early meant you had a much smaller than necessary window where you could actually adjust your speed.

The above two issues were partly caused by the IN_ApplyMoveEasing function. The function had this comment:

same as IN_ApplyEasing, but scales the output by sqrt(2). this gives diagonal stick inputs coordinates of (+/-1,+/-1).
forward/back/left/right will return +/- 1.41; this shouldn't be a problem because you can pull back on the stick to go slower (and the final speed is clamped by sv_maxspeed).

There's two things wrong with this: 1) forward/back/left/right going to 1.41 means that the walking speed will be too high, and the running speed will be clipped creating a large outer deadzone. 2) There's no need to scale things up to make diagonals output (+/-1,+/-1) instead of (+/-0.707,+/-0.707), because the latter already has magnitude 1 and anything with a magnitude higher than that will get scaled down.

  1. Added joy_outer_threshold_{look,move} CVARs which create an outer deadzone on the joysticks. Helps the player reach the max speed even if their joystick isn't able to reach its max, and it can be turned up if someone preferred the past behavior. Defaults to 0.02 (2%).

(I picked 2% because 1% and 2% are values I've seen recommended, I wanted to copy the value from a modern popular fast-paced FPS with polished controller support, and 2% is the default value in Apex Legends which happens to have an unusually detailed controller settings menu I was able to learn from.)

  1. Split the joy_deadzone CVAR into two joy_deadzone_{look,move} CVARs. Mostly done just to be a little more parallel with the joy_outer_threshold_{look,move} CVARs, and because the Kex port lets you set the joysticks' deadzones separately.
  2. Changed the default values for joy_exponent and joy_exponent_move from 3 to 2. This part of the PR is kind of just an opinion but I think it's a good one. It feels better to me, it's closer to what the Kex port does by default, and it seems like 2 is a much more commonly recommended value (this specific post by nivix (not OP) was useful to me for learning about modern joystick controls; I'm tempted to implement joystick acceleration/rampup as described there sometime to try to get closer to Kex parity). The old value 3 is maybe a little better for fine slow aiming, but it causes an awkward cliff in the middle of the joystick response curve, making it harder to do things like continuously turning the right amount to keep facing an enemy that you're strafing around.

(I felt the Kex port's joystick response curve was pretty good, so I studied its config, took videos to measure the time it takes to move a given distance or turn around at various joystick values, and charted the results against different Quakespasm joy_exponent settings: moving, turning. I still don't fully understand Kex's response curves, but it's clear to me that joy_exponent{,_move}=2 is much closer to what it does than joy_exponent{,_move}=3.)

Fixes issue where holding the movement joystick at a 45 degree angle would instead make you move at a 41 degree angle if you had "Always Run" set to "Vanilla" or at a 60 degree angle.

Fixes issue where holding the movement joystick all the way while not running would make you move at speed 283 instead of 200.

Fixes issue where while running you reach the maximum speed while holding the joystick at only 83% (when joy_exponent_move is at its default value of 3, and when joy_exponent_move is 2, 75%, and when joy_exponent_move is 1, 57%).
@sezero
Copy link
Owner

sezero commented Mar 5, 2023

@ericwa? (cortroller stuff was your baby..)

joy_sensitivity_{yaw,pitch} and joy_exponent{,_move} were both changed.

Decreasing joy_exponent{,_move} makes the joystick respond more at small
movements. joy_exponent and joy_exponent_move values of 2 give a response
curve more similar to Kex. The original value of 3 gives a response curve
that some might find better for slow precision aiming, but it creates a
sharper cliff between small inputs and large inputs that can make
smoothly adjusting your aim/movement at medium magnitudes difficult.

joy_sensitivity_{yaw,pitch} were decreased both to compensate for the
joy_exponent{,_move} change and to be closer to Kex's default.
@Macil
Copy link
Contributor Author

Macil commented Mar 6, 2023

I made one last touch to this PR: I've tweaked the final commit which changed joy_exponent (3 to 2) so that it also changes the defaults for joy_sensitivity_yaw (300 to 240) and joy_sensitivity_pitch (150 to 130). These values give max turning speeds that are the same as Kex's defaults, and decreasing these values helps to compensate for the decrease in joy_exponent (which causes mid-range inputs to be scaled up). This config is the one I use all the time in QS/vkQuake.

I didn't originally intend to have much opinionated defaults-changing stuff in this PR, but the joy_exponent_move change (3 to 2) seemed natural to pair with the movement range fixes, the joy_exponent change (3 to 2) seemed natural to pair with that, and after testing out various settings it feels best to me that this change to the sensitivity would be paired with the change to joy_exponent. The final commit isn't exactly a bugfix but I hope it fits well in a PR that's about tuning things to feel better.

@Macil Macil force-pushed the macil/fix-joystick-move-range branch from baedf23 to ad39b75 Compare March 6, 2023 05:04
@sezero
Copy link
Owner

sezero commented Mar 11, 2023

This patch is in. Thank you.

@sezero sezero closed this Mar 11, 2023
@Macil Macil deleted the macil/fix-joystick-move-range branch March 12, 2023 00:43
@ericwa
Copy link
Contributor

ericwa commented Mar 13, 2023

Thanks, these seem good to me. I'll add the new cvars to the controller section of the documentation.

Agreed, regarding the +1/+1 move inputs, it makes more sense to prioritize intuitive controls / matching what other games do, rather than emulating keyboard input as I was doing initially.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants