I've been receiving complaints from users that my game doesn't support the 16:10 aspect ratio.
You should get a more specific description of the problem. It could be that the game allows the player to select such resolutions, but the game does not look right. And that would be a different problem. You should check if your game is not stretching elements on wide screen, and that it is positioning UI elements correctly. Notice also that the perspective camera field of view is vertical, thus you may see more or less to the sides depending on the resolution.
You can try by going to the game tab on the Unity editor, on the top you will see a drop down (it says Free Aspect by default), you can change it to test your game in different aspect ratios, at the end of the list there's is a plus option to add your own. You can add an aspect ratio (select aspect ratio instead of fixed resolution) such as 16:10, or a fixed resolution such as 1680:1050.
I've found the Display class but this appears to only give the native resolution
It should give you both the "native"※ (Display.systemWidth
, Display.systemHeight
) and the current resolution (Display.renderingWidth
, Display.renderingHeight
). Screen.currentResolution
is the resolution of the screen even when windowed, while (Display.renderingWidth
, Display.renderingHeight
) is the resolution of the game, which may not match the screen resolution when windowed.
※: I believe Unity falls back to the configured resolution on Windows when native resolution information is not available. This means that the monitor could support a higher resolutions than Unity says.
not all scaled resolutions
Screen.resolutions
should give you all supported resolutions (according to Unity). You can filter that list to those that have the same aspect ratio as the native resolution (if that is what you want). To do that, iterate over Screen.resolutions
, compute the aspect ratio, and compare it to the aspect ratio of the native resolution.
By the way, if all you want is the native resolution first, you can start the list with the native resolution taken from Display
, followed by all the resolutions from Screen.resolutions
. You compare each one with the native resolution so you can skip adding that one twice.
I thought about just multiplying by some scale factor but then I'm afraid I'll get something obscure like 885x497.8
You can ignore all not integer resolutions. In fact, if you want to use divisors of the native resolution, you want to only use common divisors of the horizontal an vertical resolutions. To find the common divisors, get the gcd (greatest common divisor) with Euclid's algorithm, get get the divisors of the gcd iterating from 1
to sqrt(gcd)
and doing a simple divisibility test (eg. if (n % i == 0){/*...*/
}).
Since you only intent on supporting Windows platforms, you could sidestep Unity, and use the Windows API. You can also filter by aspect ratio if that is what you want.
First you need to get the device name. To do that, call EnumDisplayDevices
, to which you pass a pointer to a DISPLAY_DEVICEA
structure to be populated.
Once you have your device name, you can call EnumDisplaySettings
or EnumDisplaySettingsEx
. You will do multiple calls, each time with a different value of iModeNum
starting at 0 and incrementing, until the call fails. Each call gives you the information of a supported mode of the monitor in a DEVMODEA
structure. Your resolution are the fields dmPelsWidth
and dmPelsHeight
.
You can change the resolution with ChangeDisplaySettings
.
You can get the P/Invoke declaration from PInvoke.net. There is also a complete example on Stackoverflow: How to list available video modes using C#?. See also the article Dynamic Screen Resolution by sreejith ss nair at Code Project.
If you are going to be doing a lot of P/Invoke, you might be interested in a library that makes that easier, such as dahall/Vanara.
Perhaps the solution to your problem is simply to allow the player to type the desired resolution, and then change to that. You can write a coroutine that reads the resolution waiting for a change. If the resolution not changed after a while (say 5 seconds), we can assume it failed.
If the change succeeded, then wait for user input to confirm or revert (ESC). In particular, if you use ChangeDisplaySettings
to change the resolution you may end up with a black screen, in which case the player would want to revert (traditionally by pressing ESC) to get back to a supported resolution.
One more thing, you may want to figure out the minimum playable resolution for your game and not offer anything below that (in particular if you are going with the divisors of the native resolution).
Anecdotally I can tell you that I can change the resolution of my monitor to 320:240, even though that is not listed anywhere. The minimum listed by both Windows API and Unity is 640:480. The minimum on Windows configuration is 800:600 (there are ways to modify that list, but that is another tale).