499 lines
20 KiB
C#
499 lines
20 KiB
C#
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>();
|
||
}
|
||
}
|
||
}
|