- Home /
StackOverflowException problem
Hi, so I get this StackOverflowException error when trying to change graphics settings in main menu, the options also don't seem to be applied as in game mode there are no shadows when there should be. I've been looking at other posts for hours and seem to know what the issue is but cannot find what in my scrip is causing this.
The code:
using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Audio; using UnityEngine.UI; using UnityEngine.SceneManagement;
public class SettingsMenu : MonoBehaviour {
public AudioMixer mixer;
public Dropdown resolutionDropdown;
public Dropdown qualityDropdown;
public Dropdown textureDropdown;
public Dropdown aaDropdown;
public Slider volumeSlider;
public Slider slider;
Resolution[] resolutions;
// Start is called before the first frame update
void Start()
{
resolutionDropdown.ClearOptions();
List<string> options = new List<string>();
resolutions = Screen.resolutions;
int currentResolutionIndex = 0;
for (int i = 0; i < resolutions.Length; i++)
{
string option = resolutions[i].width + " x " +
resolutions[i].height;
options.Add(option);
if (resolutions[i].width == Screen.currentResolution.width
&& resolutions[i].height == Screen.currentResolution.height)
currentResolutionIndex = i;
}
resolutionDropdown.AddOptions(options);
resolutionDropdown.RefreshShownValue();
LoadSettings(currentResolutionIndex);
}
public void SetLevel(float sliderValue)
{
mixer.SetFloat("MasterVol", Mathf.Log10(sliderValue) * 20);
PlayerPrefs.SetFloat("MasterVolume", sliderValue);
}
public void SetFullscreen(bool isFullscreen)
{
Screen.fullScreen = isFullscreen;
}
public void SetResolution(int resolutionIndex)
{
Resolution resolution = resolutions[resolutionIndex];
Screen.SetResolution(resolution.width,
resolution.height, Screen.fullScreen);
}
public void SetTextureQuality(int textureIndex)
{
QualitySettings.masterTextureLimit = textureIndex;
qualityDropdown.value = 6;
}
public void SetAntiAliasing(int aaIndex)
{
QualitySettings.antiAliasing = aaIndex;
qualityDropdown.value = 6;
}
public void SetQuality(int qualityIndex)
{
if (qualityIndex != 5) // if the user is not using
//any of the presets
QualitySettings.SetQualityLevel(qualityIndex);
switch (qualityIndex)
{
case 1: // quality level - low
textureDropdown.value = 2;
aaDropdown.value = 0;
break;
case 2: // quality level - medium
textureDropdown.value = 1;
aaDropdown.value = 0;
break;
case 3: // quality level - high
textureDropdown.value = 0;
aaDropdown.value = 0;
break;
case 4: // quality level - ultra
textureDropdown.value = 0;
aaDropdown.value = 2;
break;
}
qualityDropdown.value = qualityIndex;
}
public void ExitGame()
{
Application.Quit();
}
public void SaveSettings()
{
PlayerPrefs.SetInt("QualitySettingPreference",
qualityDropdown.value);
PlayerPrefs.SetInt("ResolutionPreference",
resolutionDropdown.value);
PlayerPrefs.SetInt("TextureQualityPreference",
textureDropdown.value);
PlayerPrefs.SetInt("AntiAliasingPreference",
aaDropdown.value);
PlayerPrefs.SetInt("FullscreenPreference",
Convert.ToInt32(Screen.fullScreen));
PlayerPrefs.GetFloat("MasterVolume",
slider.value);
}
public void LoadSettings(int currentResolutionIndex)
{
if (PlayerPrefs.HasKey("QualitySettingPreference"))
qualityDropdown.value =
PlayerPrefs.GetInt("QualitySettingPreference");
else
qualityDropdown.value = 3;
if (PlayerPrefs.HasKey("ResolutionPreference"))
resolutionDropdown.value =
PlayerPrefs.GetInt("ResolutionPreference");
else
resolutionDropdown.value = currentResolutionIndex;
if (PlayerPrefs.HasKey("TextureQualityPreference"))
textureDropdown.value =
PlayerPrefs.GetInt("TextureQualityPreference");
else
textureDropdown.value = 0;
if (PlayerPrefs.HasKey("AntiAliasingPreference"))
aaDropdown.value =
PlayerPrefs.GetInt("AntiAliasingPreference");
else
aaDropdown.value = 1;
if (PlayerPrefs.HasKey("FullscreenPreference"))
Screen.fullScreen =
Convert.ToBoolean(PlayerPrefs.GetInt("FullscreenPreference"));
else
Screen.fullScreen = true;
if (PlayerPrefs.HasKey("VolumePreference"))
volumeSlider.value =
PlayerPrefs.GetFloat("VolumePreference");
else
volumeSlider.value =
PlayerPrefs.GetFloat("VolumePreference");
}
// Load game scene
public void GameScene()
{
SceneManager.LoadScene("Game");
}
}
Answer by icxrusluv · Jan 08, 2021 at 10:52 AM
I found out the issue. In calls SetTextureQuality and SetAntiAliasing it was calling for qualityIndex 6 in the dropdown while I only had 0-4, changing the value 6 to 4 on all where it was calling it fixed this issue. Thanks to everyone for the help!
Originally had plans to include more quality options than only 4 + custom.
Answer by Zaeran · Jan 07, 2021 at 04:38 PM
My guess would be your SetQuality function, assuming the qualityDropdown.onValueChanged is triggering SetQuality.
At the end of your SetQuality function, you directly set the value of qualityDropdown. Once that value is set, onValueChanged may be triggered again, which once again fires off the SetQuality event,, which sets the qualityDropdown value, which fires off the event, etc. etc.
How would I change that to not happen again but still allowing it to be changed again if the user chooses a wrong Quality setting?
I am debating whether to just try rewriting the code cause I feel like i messed it up by trying a few different things inside it and then returning back to the original version.
The only real way to tackle it would be to manually unsubscribe from the onValuechanged event, then change the value, then resubscribe to the event.
I'm not sure what that means or how to do it (fairly new to coding). But here's screenshots of the error code (too large to be posted as text) if that helps?
Answer by Bunny83 · Jan 08, 2021 at 10:30 AM
As already mentioned by Zaeran you have an infinite recursion because assigning the value of a dropdown or slider in code will also cause the OnValueChanged callback to be executed. Since you assign the value of the quality dropdown inside its own onValueChanged event this is an infinite resursion. So just remove this line as it's pointless anyways:
qualityDropdown.value = qualityIndex;
The callback is executed when the value has changed and the argument of the callback is the value that was assigned. So assigning it again makes no sense.
Would SetValueWithoutNotify be of any help here? I believe Dropdown and Slider both have this to avoid sending the changed callback.
Yes, they would help. Though they don't seem to be documented DropDown, Slider. The slider class does have a protected Set method which has a parameter to omit the callback. I don't have Unity at hand to check this. If you're sure that this method exists, feel free to post your own answer.
edit
Yep, you are right. Here's the method in the Slider class and here's the one in the DropDown class. Too bad they don't create an interface for them. Also as you can see the Slider defines the method as virtual, the DropDown not. Always those inconsistencies ^^.
Your answer
Follow this Question
Related Questions
Menu of Graphics 1 Answer
Set Graphics Emulation to No Emulation as Default? 2 Answers
Touch a box collider, quit the game. (2D) 1 Answer
Can you add more tabs in the Unity Configure Menu?? 0 Answers
Eliminate start up dialog? 1 Answer