#1 Mouse/cursor sensitivity.

My options screen

I’m currently working on a game that can be played in all the resolutions that the host machine can display. As such, I am constantly flicking between 640*480 & 1920*1080, to check the interface is clear and readable for both whenever I add something new to the HUD.

In doing so, it was bugging me that I had to keep adjusting the mouse sensitivity in my options screen. I would run at 640*480 and the cursor would fly off the screen if I breathed near the mouse. So I would drop the sensitivity right down to test the game. Then I would go to test it in 1920*1080 and find that my desk isn’t big enough for me to get the cursor from left to right, so I would up the sensitivity in my options menu again. Rinse and repeat.

This problem is compounded a thousand fold when I test things on my laptop with the crappy little track-pad.

Anyway, here’s a quick little solution I’ve just implemented to resolve this issue:

Theory:

1.) Run the game at a set resolution (let’s say 1024*768) and tweak the min and Max sensitivity values until the range feels good. (Let’s call this the base config res.)
2.) Compute actual sensitivity based on the ratio between the current screen res and that base config res.
3.) Errrrm, we’re done!

Implementation:

1.) Start with some tweakable floating point variables with which to define the min and Max sensitivities:

    float MinMouseSpeed_X = 0.24f;
    float MinMouseSpeed_Y = 0.24f;
    float MaxMouseSpeed_X = 2.3f;
    float MaxMouseSpeed_Y = 2.3f;

2.) Interpolate between these min and Max values based on a slider (or some other interface for the player to define sensitivity) ranging from 0.0f to 1.0f.

Here is a quick linear interpolation function should you need it:

    // RETURN A LINEAR INTERPOLANT (T) BETWEEN TWO FLOATS.
    float LinearInterpolate2f(float f1, float f2, float T)
    {
        T = clamp(T, 0, 1);
        return f1 + (f2-f1)*T;
    }

3.) Run the game in debug mode at the base config res (1024*768), and tweak the Min/Max variables until everything feels right.

4.) Compute the ratios between the base config res and whatever res is currently running:

    float ScreenRatioX = CURRENT_SCREEN_WIDTH/1024.0f;
    float ScreenRatioY = CURRENT_SCREEN_HEIGHT/768.0f;

5.) Get actual re-scaled mouse sensitivity values based on the user setting AND the ratio between current and default screen sizes:

(UsersSpeedSetting_X & UsersSpeedSetting_Y are floating point values between 0.0f and 1.0f representing the player’s desired sensitivity.)


float ActualMouseSpeed_X = LinearInterpolate2f(MinMouseSpeed_X, MaxMouseSpeed_X, UsersSpeedSetting_X) * ScreenRatioX;

float ActualMouseSpeed_Y = LinearInterpolate2f(MinMouseSpeed_Y, MaxMouseSpeed_Y, UsersSpeedSetting_Y) * ScreenRatioY;

And that’s it!

Now once the user has chosen mouse sensitivity values that feel right for them, they can happily run the game at new resolutions and the cursor control will feel exactly the same without the need for them to re-adjust sensitivity options.

I.E. if the screen doubles in width (or is halved), then the x_speed doubles (or halves), so the exact same amount of hand movement is required to move the cursor from left to right no matter what the resolution.

I told you this would be boring stuff. But it’s important, as anything that stops your players from getting irritated is a plus.

(Or rather, anything that does irritate them is a big minus!)

Stay tuned for more tedium, folks!
(Next time: Good frame compensation techniques. Phwoar!!)

 

Edit: Added @paul_m_firth ‘s more readable linear interpolation function.

 

 

Yawn!

Hello. I’m Nick.

I’ve been programming since I was a child, and have worked in the commercial games industry for over a decade, and as an Indie developer for over a year (working with The Indie Stone of Project Zomboid fame).

This is my new blog for tips and tricks in games programming.

 

However, unlike conventional gamedev blogs, I intend to cover topics which whilst I find very important, often get overlooked and never discussed due to their boring/dry nature.

 

Pillows on standby, folks!