Files
megakoop/UI/Scripts/UGUIMainMenuController.cs
2025-11-01 18:15:05 +01:00

499 lines
20 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
using TMPro;
#else
using TMPro;
#endif
using System.Collections.Generic;
namespace MegaKoop.UI
{
/// <summary>
/// UGUI Main Menu controller (no UI Toolkit). Handles switching panels and basic settings.
/// </summary>
public class UGUIMainMenuController : MonoBehaviour
{
// Panels
[Header("Optional Panel Refs (assign to override auto-find)")]
[SerializeField] private GameObject panelMainRef;
[SerializeField] private GameObject panelSettingsRef;
[SerializeField] private GameObject panelLobbyRef;
private GameObject panelMain;
private GameObject panelSettings;
private GameObject panelLobby;
[Header("Manual Wiring - Main Menu Buttons")]
[SerializeField] private Button btnMultiplayer;
[SerializeField] private Button btnSettings;
[SerializeField] private Button btnQuit;
[Header("Manual Wiring - Settings Controls")]
[SerializeField] private TMP_Dropdown ddQuality;
[SerializeField] private Toggle tgFullscreen;
[SerializeField] private TMP_Dropdown ddResolution;
[SerializeField] private Button btnApplySettings;
[SerializeField] private Button btnBackFromSettings;
[SerializeField] private Slider slMaster;
[SerializeField] private Slider slMusic;
[SerializeField] private Slider slSFX;
private void Awake()
{
// Panels (created by UGUIMenuBuilder) najdi i když jsou neaktivní
RefreshPanelReferences();
// Buttons
btnMultiplayer = EnsureButton(btnMultiplayer, "Button_Multiplayer", panelMain ? panelMain.transform : this.transform);
btnSettings = EnsureButton(btnSettings, "Button_Settings", panelMain ? panelMain.transform : this.transform);
btnQuit = EnsureButton(btnQuit, "Button_Quit", panelMain ? panelMain.transform : this.transform);
// Settings
ddQuality = EnsureDropdown(ddQuality, "Dropdown_Quality", panelSettings ? panelSettings.transform : this.transform);
tgFullscreen = EnsureToggle(tgFullscreen, "Toggle_Fullscreen", panelSettings ? panelSettings.transform : this.transform);
ddResolution = EnsureDropdown(ddResolution, "Dropdown_Resolution", panelSettings ? panelSettings.transform : this.transform);
btnApplySettings = EnsureButton(btnApplySettings, "Button_ApplySettings", panelSettings ? panelSettings.transform : this.transform);
btnBackFromSettings = EnsureButton(btnBackFromSettings, "Button_BackFromSettings", panelSettings ? panelSettings.transform : this.transform);
slMaster = EnsureSlider(slMaster, "Slider_MasterVolume", panelSettings ? panelSettings.transform : this.transform);
slMusic = EnsureSlider(slMusic, "Slider_MusicVolume", panelSettings ? panelSettings.transform : this.transform);
slSFX = EnsureSlider(slSFX, "Slider_SFXVolume", panelSettings ? panelSettings.transform : this.transform);
if (!btnApplySettings && panelSettings) btnApplySettings = FindButtonByLabel("APPLY", panelSettings.transform);
if (!btnBackFromSettings && panelSettings) btnBackFromSettings = FindButtonByLabel("BACK", panelSettings.transform);
WireEvents();
InitializeSettingsUI();
// Ensure initial panels
ShowMainMenu();
}
// Allow UGUIMenuBuilder to inject panel refs directly
public void SetPanels(GameObject main, GameObject settings, GameObject lobby)
{
panelMainRef = main;
panelSettingsRef = settings;
panelLobbyRef = lobby;
RefreshPanelReferences();
}
public void SetMainMenuButtons(Button multiplayerButton, Button settingsButton, Button quitButton)
{
btnMultiplayer = multiplayerButton;
btnSettings = settingsButton;
btnQuit = quitButton;
}
public void SetSettingsControls(TMP_Dropdown qualityDropdown, Toggle fullscreenToggle,
TMP_Dropdown resolutionDropdown, Slider masterVolume, Slider musicVolume, Slider sfxVolume,
Button applyButton, Button backButton)
{
ddQuality = qualityDropdown;
tgFullscreen = fullscreenToggle;
ddResolution = resolutionDropdown;
slMaster = masterVolume;
slMusic = musicVolume;
slSFX = sfxVolume;
btnApplySettings = applyButton;
btnBackFromSettings = backButton;
}
private void RefreshPanelReferences()
{
panelMain = panelMainRef ? panelMainRef : (FindAnyInScene("Panel_MainMenu") ?? panelMain);
panelSettings = panelSettingsRef ? panelSettingsRef : (FindAnyInScene("Panel_Settings") ?? panelSettings);
panelLobby = panelLobbyRef ? panelLobbyRef : (FindAnyInScene("Panel_Lobby") ?? panelLobby);
}
private Button EnsureButton(Button existing, string name, Transform scope)
{
if (existing) return existing;
return FindButton(name, scope);
}
private TMP_Dropdown EnsureDropdown(TMP_Dropdown existing, string name, Transform scope)
{
if (existing) return existing;
return FindDropdown(name, scope);
}
private Toggle EnsureToggle(Toggle existing, string name, Transform scope)
{
if (existing) return existing;
return FindToggle(name, scope);
}
private Slider EnsureSlider(Slider existing, string name, Transform scope)
{
if (existing) return existing;
return FindSlider(name, scope);
}
private GameObject FindAnyInScene(string name)
{
// Najde i neaktivní objekty
var all = Resources.FindObjectsOfTypeAll<Transform>();
foreach (var t in all)
{
if (t.hideFlags != HideFlags.None) continue;
var go = t.gameObject;
if (!go.scene.IsValid() || !go.scene.isLoaded) continue;
if (go.name == name) return go;
}
return null;
}
private Button FindButton(string name, Transform scope = null)
{
if (scope != null)
{
var comps = scope.GetComponentsInChildren<Button>(true);
foreach (var c in comps)
{
if (c && c.name == name) return c;
}
return null;
}
var all = Resources.FindObjectsOfTypeAll<Button>();
foreach (var c in all)
{
if (c && c.name == name && c.gameObject.scene.IsValid() && c.gameObject.scene.isLoaded) return c;
}
return null;
}
private TMP_Dropdown FindDropdown(string name, Transform scope = null)
{
if (scope != null)
{
var comps = scope.GetComponentsInChildren<TMP_Dropdown>(true);
foreach (var c in comps)
{
if (c && c.name == name) return c;
}
return null;
}
var all = Resources.FindObjectsOfTypeAll<TMP_Dropdown>();
foreach (var c in all)
{
if (c && c.name == name && c.gameObject.scene.IsValid() && c.gameObject.scene.isLoaded) return c;
}
return null;
}
private Toggle FindToggle(string name, Transform scope = null)
{
if (scope != null)
{
var comps = scope.GetComponentsInChildren<Toggle>(true);
foreach (var c in comps)
{
if (c && c.name == name) return c;
}
return null;
}
var all = Resources.FindObjectsOfTypeAll<Toggle>();
foreach (var c in all)
{
if (c && c.name == name && c.gameObject.scene.IsValid() && c.gameObject.scene.isLoaded) return c;
}
return null;
}
private Slider FindSlider(string name, Transform scope = null)
{
if (scope != null)
{
var comps = scope.GetComponentsInChildren<Slider>(true);
foreach (var c in comps)
{
if (c && c.name == name) return c;
}
return null;
}
var all = Resources.FindObjectsOfTypeAll<Slider>();
foreach (var c in all)
{
if (c && c.name == name && c.gameObject.scene.IsValid() && c.gameObject.scene.isLoaded) return c;
}
return null;
}
private Button FindButtonByLabel(string label, Transform scope)
{
if (!scope) return null;
var btns = scope.GetComponentsInChildren<Button>(true);
for (int i = 0; i < btns.Length; i++)
{
var t = btns[i].GetComponentInChildren<TextMeshProUGUI>(true);
if (t && string.Equals(t.text?.Trim(), label, System.StringComparison.OrdinalIgnoreCase))
return btns[i];
}
return null;
}
private void WireEvents()
{
if (btnMultiplayer) btnMultiplayer.onClick.AddListener(OnOpenMultiplayer); else Debug.LogWarning("[UGUIMainMenu] Button_Multiplayer not found");
if (btnSettings) btnSettings.onClick.AddListener(OnOpenSettings); else Debug.LogWarning("[UGUIMainMenu] Button_Settings not found");
if (btnQuit) btnQuit.onClick.AddListener(OnQuit); else Debug.LogWarning("[UGUIMainMenu] Button_Quit not found");
if (btnApplySettings) btnApplySettings.onClick.AddListener(OnApplySettings); else Debug.LogWarning("[UGUIMainMenu] Button_ApplySettings not found");
if (btnBackFromSettings) btnBackFromSettings.onClick.AddListener(ShowMainMenu); else Debug.LogWarning("[UGUIMainMenu] Button_BackFromSettings not found");
if (ddQuality) ddQuality.onValueChanged.AddListener(i => { Debug.Log("[UGUIMainMenu] Quality changed to index " + i); ddQuality.RefreshShownValue(); });
if (ddResolution) ddResolution.onValueChanged.AddListener(i => { Debug.Log("[UGUIMainMenu] Resolution changed to index " + i); ddResolution.RefreshShownValue(); });
if (tgFullscreen) tgFullscreen.onValueChanged.AddListener(v => { Debug.Log("[UGUIMainMenu] Fullscreen " + v); });
if (slMaster) slMaster.onValueChanged.AddListener(v => { AudioListener.volume = v / 100f; });
}
private void ShowMainMenu()
{
if (panelMain) panelMain.SetActive(true);
if (panelSettings) panelSettings.SetActive(false);
if (panelLobby) panelLobby.SetActive(false);
}
private void OnOpenMultiplayer()
{
RefreshPanelReferences();
bool showed = false;
if (panelLobby)
{
if (panelMain) panelMain.SetActive(false);
if (panelSettings) panelSettings.SetActive(false);
panelLobby.SetActive(true);
showed = true;
}
UGUIMultiplayerLobbyController lobby;
#if UNITY_2023_1_OR_NEWER
lobby = Object.FindFirstObjectByType<UGUIMultiplayerLobbyController>();
#else
lobby = Object.FindObjectOfType<UGUIMultiplayerLobbyController>();
#endif
if (lobby && showed) lobby.QuickHost(4, true);
if (!showed)
{
Debug.LogError("[UGUIMainMenu] Panel_Lobby not found in scene. Did you run Tools > MegaKoop > Generate UGUI Main Menu?" );
if (panelMain) panelMain.SetActive(true);
}
}
private void OnOpenSettings()
{
if (panelMain) panelMain.SetActive(false);
if (panelSettings) panelSettings.SetActive(true);
if (panelLobby) panelLobby.SetActive(false);
Debug.Log("[UGUIMainMenu] Open Settings");
}
private void OnQuit()
{
#if UNITY_EDITOR
EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
}
private void ApplySettings()
{
if (ddQuality)
{
QualitySettings.SetQualityLevel(ddQuality.value, true);
}
if (tgFullscreen)
{
Screen.fullScreen = tgFullscreen.isOn;
}
if (ddResolution)
{
if (ddResolution.options != null && ddResolution.options.Count > 0 && ddResolution.value >= 0 && ddResolution.value < ddResolution.options.Count)
{
var opt = ddResolution.options[ddResolution.value].text; // e.g., "1920x1080"
var parts = opt.ToLower().Split('x');
if (parts.Length == 2 && int.TryParse(parts[0], out int w) && int.TryParse(parts[1], out int h))
{
Screen.SetResolution(w, h, Screen.fullScreenMode);
}
}
}
if (slMaster)
{
AudioListener.volume = slMaster.value / 100f;
}
}
private void OnApplySettings()
{
ApplySettings();
SaveSettings();
ShowMainMenu();
Debug.Log("[UGUIMainMenu] Apply & Back to Main");
}
private void InitializeSettingsUI()
{
if (ddQuality)
{
var names = QualitySettings.names;
if (names != null && names.Length > 0)
{
ddQuality.ClearOptions();
ddQuality.AddOptions(new List<string>(names));
ddQuality.value = Mathf.Clamp(QualitySettings.GetQualityLevel(), 0, ddQuality.options.Count - 1);
ddQuality.RefreshShownValue();
}
ddQuality.interactable = true;
FixDropdownRaycasts(ddQuality);
SetupDropdownTemplateCanvas(ddQuality);
}
if (ddResolution)
{
var seen = new HashSet<string>();
var opts = new List<string>();
string cur = Screen.currentResolution.width + "x" + Screen.currentResolution.height;
int curIdx = 0;
foreach (var r in Screen.resolutions)
{
string s = r.width + "x" + r.height;
if (seen.Add(s))
{
if (s == cur) curIdx = opts.Count;
opts.Add(s);
}
}
if (opts.Count == 0)
{
opts.Add(cur);
curIdx = 0;
}
ddResolution.ClearOptions();
ddResolution.AddOptions(opts);
ddResolution.value = Mathf.Clamp(curIdx, 0, ddResolution.options.Count - 1);
ddResolution.RefreshShownValue();
ddResolution.interactable = true;
FixDropdownRaycasts(ddResolution);
SetupDropdownTemplateCanvas(ddResolution);
}
if (tgFullscreen)
{
tgFullscreen.isOn = Screen.fullScreen;
tgFullscreen.interactable = true;
}
LoadSettings();
}
private void SaveSettings()
{
if (ddQuality) PlayerPrefs.SetInt("QualityLevel", ddQuality.value);
PlayerPrefs.SetInt("Fullscreen", Screen.fullScreen ? 1 : 0);
if (ddResolution && ddResolution.options.Count > 0)
{
var opt = ddResolution.options[ddResolution.value].text;
var parts = opt.Split('x');
if (parts.Length == 2 && int.TryParse(parts[0], out int w) && int.TryParse(parts[1], out int h))
{
PlayerPrefs.SetInt("ResolutionWidth", w);
PlayerPrefs.SetInt("ResolutionHeight", h);
}
}
if (slMaster) PlayerPrefs.SetFloat("MasterVolume", slMaster.value);
if (slMusic) PlayerPrefs.SetFloat("MusicVolume", slMusic.value);
if (slSFX) PlayerPrefs.SetFloat("SFXVolume", slSFX.value);
PlayerPrefs.Save();
}
private void LoadSettings()
{
if (ddQuality && ddQuality.options.Count > 0)
{
int q = PlayerPrefs.GetInt("QualityLevel", QualitySettings.GetQualityLevel());
ddQuality.value = Mathf.Clamp(q, 0, ddQuality.options.Count - 1);
ddQuality.RefreshShownValue();
}
if (tgFullscreen)
{
bool full = PlayerPrefs.GetInt("Fullscreen", Screen.fullScreen ? 1 : 0) == 1;
tgFullscreen.isOn = full;
}
if (ddResolution && ddResolution.options.Count > 0)
{
int w = PlayerPrefs.GetInt("ResolutionWidth", Screen.currentResolution.width);
int h = PlayerPrefs.GetInt("ResolutionHeight", Screen.currentResolution.height);
string key = w + "x" + h;
int idx = ddResolution.options.FindIndex(o => o.text == key);
if (idx >= 0)
{
ddResolution.value = idx;
ddResolution.RefreshShownValue();
}
}
if (slMaster)
{
var mv = PlayerPrefs.GetFloat("MasterVolume", 100f);
slMaster.value = mv;
AudioListener.volume = mv / 100f;
}
if (slMusic)
{
slMusic.value = PlayerPrefs.GetFloat("MusicVolume", 80f);
}
if (slSFX)
{
slSFX.value = PlayerPrefs.GetFloat("SFXVolume", 100f);
}
}
private void FixDropdownRaycasts(TMP_Dropdown dd)
{
if (!dd || dd.template == null) return;
var tpl = dd.template;
var vp = tpl.Find("Viewport");
if (vp)
{
var img = vp.GetComponent<Image>();
if (img) img.raycastTarget = false;
}
}
private void SetupDropdownTemplateCanvas(TMP_Dropdown dd)
{
if (!dd || dd.template == null) return;
var tpl = dd.template;
var cv = tpl.GetComponent<Canvas>();
if (cv == null) cv = tpl.gameObject.AddComponent<Canvas>();
cv.overrideSorting = true;
cv.sortingOrder = 5000;
if (!tpl.GetComponent<GraphicRaycaster>()) tpl.gameObject.AddComponent<GraphicRaycaster>();
}
private void FixDropdownRaycasts(Dropdown dd)
{
if (!dd || dd.template == null) return;
var tpl = dd.template;
var vp = tpl.Find("Viewport");
if (vp)
{
var img = vp.GetComponent<Image>();
if (img) img.raycastTarget = false;
}
}
private void SetupDropdownTemplateCanvas(Dropdown dd)
{
if (!dd || dd.template == null) return;
var tpl = dd.template;
var cv = tpl.GetComponent<Canvas>();
if (cv == null) cv = tpl.gameObject.AddComponent<Canvas>();
cv.overrideSorting = true;
cv.sortingOrder = 5000;
if (!tpl.GetComponent<GraphicRaycaster>()) tpl.gameObject.AddComponent<GraphicRaycaster>();
}
}
}