Hi
I have a script that I’m using for a “settings menu” for my game, to allow the player to set the resolution. This script gathers the display’s supported resolutions and lists them out in a text field, but it also “filters” out multiples of the same resolution at lower refresh rates. I’ve done this because otherwise it just creates a mess of resolutions like 1920x1080@59hz, 1920x1080@60hz, 1920x1080@75hz and so on.
This works properly when I launch it on my native monitor, but as soon as I close the game, switch it to my other monitor, and then launch it again, it gives an “Index was out of range” error.
The thing is, my native monitor supports refresh rates up to 144hz, and the external monitor up to 60hz. I think this causes the issue as Unity runs the game, saves those resolutions as a list in the player prefs, and the external monitor reads them but doesn’t support any of those 144hz resolutions, which is why it returns 0 “filtered resolutions”.
Disclaimer: I’m not a coder and cobbled this together through various tutorials and the help of a coder friend, so the script might be a bit messy. You may also ignore the vsync and fullscreen parts.
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class OptionsQualitySettings5B : MonoBehaviour
{
#region Attributes
#region Player Pref Key Constants
private const string RESOLUTION_PREF_KEY = "resolution";
#endregion
#region Resolution
[SerializeField]
private TMP_Text resolutionText;
public Toggle fullscreenToggle, vsyncToggle;
private Resolution[] resolutions;
private int currentResolutionIndex = 0;
private List<Resolution> filteredResolutions;
private float currentRefreshRate;
#endregion
#endregion
void Start()
{
resolutions = Screen.resolutions;
filteredResolutions = new List<Resolution>();
currentRefreshRate = Screen.currentResolution.refreshRate;
CreateFilteredListOfResolutions();
//currentResolutionIndex = PlayerPrefs.GetInt(RESOLUTION_PREF_KEY, 0);
//SetResolutionText(filteredResolutions[currentResolutionIndex]);
//SetAndApplyResolution(currentResolutionIndex);
currentResolutionIndex = GetTheResolutionIndex();
if (currentResolutionIndex > -1)
{
SetResolutionText(filteredResolutions[currentResolutionIndex]);
SetAndApplyResolution(currentResolutionIndex);
}
fullscreenToggle.isOn = Screen.fullScreen;
if (QualitySettings.vSyncCount == 0)
{
vsyncToggle.isOn = false;
}
else
{
vsyncToggle.isOn = true;
}
foreach (var res in resolutions)
{
Debug.Log(res.width + "x" + res.height + " : " + res.refreshRate);
}
}
int GetTheResolutionIndex()
{
// load index from saved settings (0 if there are none)
int index = PlayerPrefs.GetInt(RESOLUTION_PREF_KEY, 0);
if (filteredResolutions.Count == 0)
{
Debug.LogError($"No resolutions detected by Unity so there is none what we can set.");
return -1;
}
else if (index > filteredResolutions.Count)
{
Debug.LogWarning($"Resolution loaded from memory had bigger number that how many were detected by Unity ({filteredResolutions.Count}), so it was changed to index 0 (first one in detected list).");
index = 0;
}
return index;
}
#region Resolution Cycling
private void SetResolutionText(Resolution resolution)
{
resolutionText.text = resolution.width + "x" + resolution.height + " @" + resolution.refreshRate + " Hz"; ;
}
public void SetNextResolution()
{
if (currentResolutionIndex < 0)
{
ShowResolutionIndexError();
return;
}
currentResolutionIndex = GetNextWrappedIndex(filteredResolutions, currentResolutionIndex);
SetResolutionText(filteredResolutions[currentResolutionIndex]);
}
public void SetPreviousResolution()
{
if (currentResolutionIndex < 0)
{
ShowResolutionIndexError();
return;
}
currentResolutionIndex = GetPreviousWrappedIndex(filteredResolutions, currentResolutionIndex);
SetResolutionText(filteredResolutions[currentResolutionIndex]);
}
void ShowResolutionIndexError()
{
Debug.LogError("ResolutionIndex is -1 what means that no resolutions were detected and this function can't do anything.");
}
#endregion
#region Apply Resolution
private void SetAndApplyResolution(int newResolutionIndex)
{
if (currentResolutionIndex < 0)
{
ShowResolutionIndexError();
return;
}
currentResolutionIndex = newResolutionIndex;
ApplyCurrentResolution();
}
private void ApplyCurrentResolution()
{
ApplyResolution(filteredResolutions[currentResolutionIndex]);
}
private void ApplyResolution(Resolution resolution)
{
SetResolutionText(resolution);
Screen.SetResolution(resolution.width, resolution.height, fullscreenToggle.isOn);
PlayerPrefs.SetInt(RESOLUTION_PREF_KEY, currentResolutionIndex);
if (vsyncToggle.isOn)
{
QualitySettings.vSyncCount = 1;
}
else
{
QualitySettings.vSyncCount = 0;
}
}
#endregion
#region Misc Helpers
#region Index Wrap Helpers
private int GetNextWrappedIndex<T>(IList<T> collection, int currentIndex)
{
if (collection.Count < 1) return 0;
return (currentIndex + 1) % collection.Count;
}
private int GetPreviousWrappedIndex<T>(IList<T> collection, int currentIndex)
{
if (collection.Count < 1) return 0;
if ((currentIndex - 1) < 0) return collection.Count - 1;
return (currentIndex - 1) % collection.Count;
}
#endregion
#endregion
public void ApplyChanges()
{
SetAndApplyResolution(currentResolutionIndex);
}
// Filtering of resolutions by current refreshrate
void CreateFilteredListOfResolutions()
{
for (int i = 0; i < resolutions.Length; i++)
{
if (resolutions[i].refreshRate == currentRefreshRate)
{
filteredResolutions.Add(resolutions[i]);
}
}
}
}
There was also this comment on one of the tutorials that might help:
So is this a known problem with Unity? Is it fixable at all? Thanks for any help!