Kursach_StealthAction/Assets/Scripts/PauseMenu.cs

573 lines
19 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 System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using UnityEngine.InputSystem;
public class PauseMenu : MonoBehaviour
{
[Header("Панели")]
public GameObject pauseMenuPanel;
public GameObject settingsPanel;
[Header("Кнопки панели действий")]
public Button resumeButton;
public Button restartButton;
public Button mainMenuButton;
public Button quitButton;
[Header("Вкладки")]
public Button[] tabButtons;
public GameObject[] tabPanels;
[Header("Настройки: Звук")]
public Slider volumeSlider;
public Text volumeValueText;
public Toggle muteToggle;
[Header("Настройки: Графика")]
public Dropdown qualityDropdown;
public Toggle fullscreenToggle;
public Dropdown resolutionDropdown;
public Toggle vsyncToggle;
[Header("Настройки: Управление")]
public Slider sensitivitySlider;
public Text sensitivityValueText;
public Toggle invertYToggle;
private bool isPaused = false;
private bool isInitializing = false;
private bool wasCursorLocked = false;
private List<Resolution> filteredResolutions = new List<Resolution>();
public bool IsPaused => isPaused;
private void Awake()
{
AutoWireUI();
}
private void Start()
{
AutoWireUI();
if (pauseMenuPanel != null) pauseMenuPanel.SetActive(false);
if (settingsPanel != null && settingsPanel != pauseMenuPanel) settingsPanel.SetActive(false);
SetupActionButtons();
SetupTabs();
InitializeSettingsUI();
wasCursorLocked = (Cursor.lockState == CursorLockMode.Locked);
}
private void Update()
{
// Не открываем меню паузы, если активен экран смерти
if (DeathScreenUI.Instance != null && DeathScreenUI.Instance.IsShown) return;
bool togglePause = false;
var keyboard = Keyboard.current;
if (keyboard != null)
{
if (keyboard.escapeKey.wasPressedThisFrame ||
keyboard.pKey.wasPressedThisFrame ||
keyboard.tabKey.wasPressedThisFrame ||
keyboard.pauseKey.wasPressedThisFrame)
{
togglePause = true;
}
}
var gamepad = Gamepad.current;
if (gamepad != null && gamepad.startButton.wasPressedThisFrame)
{
togglePause = true;
}
#if UNITY_EDITOR
// В Unity Editor при заблокированном курсоре нажатие Escape перехватывается редактором
// для снятия блокировки курсора (Cursor.lockState переключается в None) и не передается в Update().
// Поэтому в редакторе переключение lockState из Locked в None трактуется как нажатие Escape!
if (!isPaused && wasCursorLocked && Cursor.lockState != CursorLockMode.Locked)
{
togglePause = true;
}
wasCursorLocked = (Cursor.lockState == CursorLockMode.Locked);
#endif
if (togglePause)
{
if (isPaused)
{
if (settingsPanel != null && settingsPanel.activeSelf && settingsPanel != pauseMenuPanel)
{
CloseSettings();
}
else
{
ResumeGame();
}
}
else
{
PauseGame();
}
}
}
public void PauseGame()
{
isPaused = true;
Time.timeScale = 0f;
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
wasCursorLocked = false;
if (pauseMenuPanel != null)
{
pauseMenuPanel.SetActive(true);
SwitchTab(0);
}
if (settingsPanel != null && settingsPanel != pauseMenuPanel)
{
settingsPanel.SetActive(false);
}
Debug.Log("[PauseMenu] Game PAUSED (Esc/P/Tab pressed). Time.timeScale=0.");
}
public void ResumeGame()
{
isPaused = false;
Time.timeScale = 1f;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
wasCursorLocked = true;
if (pauseMenuPanel != null) pauseMenuPanel.SetActive(false);
if (settingsPanel != null) settingsPanel.SetActive(false);
Debug.Log("[PauseMenu] Game RESUMED. Time.timeScale=1.");
}
public void RestartGame()
{
Time.timeScale = 1f;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
public void OpenSettings()
{
if (pauseMenuPanel != null) pauseMenuPanel.SetActive(false);
if (settingsPanel != null) settingsPanel.SetActive(true);
}
public void CloseSettings()
{
PlayerPrefs.Save();
if (settingsPanel != null) settingsPanel.SetActive(false);
if (pauseMenuPanel != null) pauseMenuPanel.SetActive(true);
}
public void ReturnToMainMenu()
{
Time.timeScale = 1f;
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
SceneManager.LoadScene("MainMenu");
}
public void QuitGame()
{
PlayerPrefs.Save();
Application.Quit();
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#endif
}
public void SwitchTab(int tabIndex)
{
if (tabPanels != null)
{
for (int i = 0; i < tabPanels.Length; i++)
{
if (tabPanels[i] != null)
{
tabPanels[i].SetActive(i == tabIndex);
}
}
}
if (tabButtons != null)
{
for (int i = 0; i < tabButtons.Length; i++)
{
if (tabButtons[i] != null)
{
bool isActive = (i == tabIndex);
var img = tabButtons[i].GetComponent<Image>();
if (img != null)
{
img.color = isActive
? new Color(0.00f, 0.65f, 0.85f, 0.95f) // Неоновый бирюзовый акцент
: new Color(0.06f, 0.10f, 0.16f, 0.85f); // Темный фон неактивной вкладки
}
var text = tabButtons[i].GetComponentInChildren<Text>();
if (text != null)
{
text.color = isActive
? Color.white
: new Color(0.40f, 0.55f, 0.65f, 0.80f);
}
}
}
}
}
private void SetupTabs()
{
if (tabButtons != null)
{
for (int i = 0; i < tabButtons.Length; i++)
{
int index = i;
tabButtons[i].onClick.RemoveAllListeners();
tabButtons[i].onClick.AddListener(() => SwitchTab(index));
}
}
}
private void SetupActionButtons()
{
if (resumeButton != null)
{
resumeButton.onClick.RemoveAllListeners();
resumeButton.onClick.AddListener(ResumeGame);
}
if (restartButton != null)
{
restartButton.onClick.RemoveAllListeners();
restartButton.onClick.AddListener(RestartGame);
}
if (mainMenuButton != null)
{
mainMenuButton.onClick.RemoveAllListeners();
mainMenuButton.onClick.AddListener(ReturnToMainMenu);
}
if (quitButton != null)
{
quitButton.onClick.RemoveAllListeners();
quitButton.onClick.AddListener(QuitGame);
}
}
public void AutoWireUI()
{
if (pauseMenuPanel == null)
{
var root = transform.Find("PauseRootPanel");
if (root != null)
{
pauseMenuPanel = root.gameObject;
}
else
{
var panel = transform.Find("PauseMenuPanel");
if (panel != null) pauseMenuPanel = panel.gameObject;
}
}
Transform window = transform.Find("PauseRootPanel/Settings_Window");
if (window != null)
{
var winRt = window.GetComponent<RectTransform>();
if (winRt != null && (winRt.sizeDelta.x <= 0f || winRt.sizeDelta.y <= 0f))
{
winRt.anchorMin = new Vector2(0.5f, 0.5f);
winRt.anchorMax = new Vector2(0.5f, 0.5f);
winRt.pivot = new Vector2(0.5f, 0.5f);
winRt.anchoredPosition = Vector2.zero;
winRt.sizeDelta = new Vector2(1100f, 720f);
}
Transform dock = window.Find("Bottom_Action_Dock");
if (dock != null)
{
if (resumeButton == null) resumeButton = dock.Find("Btn_Resume")?.GetComponent<Button>();
if (restartButton == null) restartButton = dock.Find("Btn_Restart")?.GetComponent<Button>();
if (mainMenuButton == null) mainMenuButton = dock.Find("Btn_MainMenu")?.GetComponent<Button>();
if (quitButton == null) quitButton = dock.Find("Btn_Quit")?.GetComponent<Button>();
}
Transform tabBar = window.Find("Tab_Bar");
Transform content = window.Find("Content_Area");
if (tabBar != null && (tabButtons == null || tabButtons.Length == 0))
{
tabButtons = new Button[tabBar.childCount];
for (int i = 0; i < tabBar.childCount; i++)
{
tabButtons[i] = tabBar.GetChild(i).GetComponent<Button>();
}
}
if (content != null && (tabPanels == null || tabPanels.Length == 0))
{
tabPanels = new GameObject[]
{
content.Find("Panel_Audio")?.gameObject,
content.Find("Panel_Graphics")?.gameObject,
content.Find("Panel_Controls")?.gameObject,
content.Find("Panel_Briefing")?.gameObject
};
}
if (volumeSlider == null) volumeSlider = content?.Find("Panel_Audio/Row_Volume/Slider")?.GetComponent<Slider>();
if (volumeValueText == null) volumeValueText = content?.Find("Panel_Audio/Row_Volume/ValueText")?.GetComponent<Text>();
if (muteToggle == null) muteToggle = content?.Find("Panel_Audio/Row_Mute/Toggle")?.GetComponent<Toggle>();
if (qualityDropdown == null) qualityDropdown = content?.Find("Panel_Graphics/Row_Quality/Dropdown")?.GetComponent<Dropdown>();
if (fullscreenToggle == null) fullscreenToggle = content?.Find("Panel_Graphics/Row_Fullscreen/Toggle")?.GetComponent<Toggle>();
if (resolutionDropdown == null) resolutionDropdown = content?.Find("Panel_Graphics/Row_Resolution/Dropdown")?.GetComponent<Dropdown>();
if (vsyncToggle == null) vsyncToggle = content?.Find("Panel_Graphics/Row_Vsync/Toggle")?.GetComponent<Toggle>();
if (sensitivitySlider == null) sensitivitySlider = content?.Find("Panel_Controls/Row_Sensitivity/Slider")?.GetComponent<Slider>();
if (sensitivityValueText == null) sensitivityValueText = content?.Find("Panel_Controls/Row_Sensitivity/ValueText")?.GetComponent<Text>();
if (invertYToggle == null) invertYToggle = content?.Find("Panel_Controls/Row_InvertY/Toggle")?.GetComponent<Toggle>();
}
}
private void InitializeSettingsUI()
{
isInitializing = true;
// Звук
float savedVolume = PlayerPrefs.GetFloat(GameSettings.KeyMasterVolume, 1.0f);
bool savedMute = PlayerPrefs.GetInt(GameSettings.KeyIsMuted, 0) == 1;
if (volumeSlider != null)
{
volumeSlider.minValue = 0f;
volumeSlider.maxValue = 1f;
volumeSlider.value = savedVolume;
volumeSlider.onValueChanged.RemoveAllListeners();
volumeSlider.onValueChanged.AddListener(OnVolumeChanged);
}
if (muteToggle != null)
{
muteToggle.isOn = savedMute;
muteToggle.onValueChanged.RemoveAllListeners();
muteToggle.onValueChanged.AddListener(OnMuteChanged);
}
UpdateVolumeLabel(savedVolume, savedMute);
// Качество графики
if (qualityDropdown != null)
{
qualityDropdown.ClearOptions();
List<string> options = new List<string>();
foreach (var q in QualitySettings.names)
{
options.Add(TranslateQuality(q));
}
qualityDropdown.AddOptions(options);
qualityDropdown.value = PlayerPrefs.GetInt(GameSettings.KeyQualityLevel, QualitySettings.GetQualityLevel());
qualityDropdown.RefreshShownValue();
qualityDropdown.onValueChanged.RemoveAllListeners();
qualityDropdown.onValueChanged.AddListener(OnQualityChanged);
}
// Полноэкранный режим
if (fullscreenToggle != null)
{
fullscreenToggle.isOn = PlayerPrefs.GetInt(GameSettings.KeyFullscreen, Screen.fullScreen ? 1 : 0) == 1;
fullscreenToggle.onValueChanged.RemoveAllListeners();
fullscreenToggle.onValueChanged.AddListener(OnFullscreenChanged);
}
// Разрешения экрана
PopulateResolutions();
// Вертикальная синхронизация
if (vsyncToggle != null)
{
vsyncToggle.isOn = QualitySettings.vSyncCount > 0;
vsyncToggle.onValueChanged.RemoveAllListeners();
vsyncToggle.onValueChanged.AddListener(OnVsyncChanged);
}
// Чувствительность
float savedSens = PlayerPrefs.GetFloat(GameSettings.KeyMouseSensitivity, 1.0f);
if (sensitivitySlider != null)
{
sensitivitySlider.minValue = 0.2f;
sensitivitySlider.maxValue = 3.0f;
sensitivitySlider.value = savedSens;
sensitivitySlider.onValueChanged.RemoveAllListeners();
sensitivitySlider.onValueChanged.AddListener(OnSensitivityChanged);
}
UpdateSensitivityLabel(savedSens);
// Инверсия по Y
if (invertYToggle != null)
{
invertYToggle.isOn = PlayerPrefs.GetInt("Settings_InvertY", 0) == 1;
invertYToggle.onValueChanged.RemoveAllListeners();
invertYToggle.onValueChanged.AddListener(OnInvertYChanged);
}
isInitializing = false;
}
private void PopulateResolutions()
{
if (resolutionDropdown == null) return;
resolutionDropdown.ClearOptions();
var allRes = Screen.resolutions;
filteredResolutions.Clear();
var options = new List<string>();
var seen = new HashSet<string>();
for (int i = allRes.Length - 1; i >= 0; i--)
{
var res = allRes[i];
string key = $"{res.width}x{res.height}";
if (!seen.Contains(key))
{
seen.Add(key);
filteredResolutions.Insert(0, res);
}
}
if (filteredResolutions.Count == 0)
{
filteredResolutions.Add(new Resolution { width = 1920, height = 1080 });
filteredResolutions.Add(new Resolution { width = 1280, height = 720 });
}
int currentIdx = 0;
int curW = Screen.width;
int curH = Screen.height;
for (int i = 0; i < filteredResolutions.Count; i++)
{
var r = filteredResolutions[i];
options.Add($"{r.width} x {r.height}");
if (r.width == curW && r.height == curH)
{
currentIdx = i;
}
}
resolutionDropdown.AddOptions(options);
resolutionDropdown.value = currentIdx;
resolutionDropdown.RefreshShownValue();
resolutionDropdown.onValueChanged.RemoveAllListeners();
resolutionDropdown.onValueChanged.AddListener(OnResolutionChanged);
}
private void OnResolutionChanged(int index)
{
if (isInitializing || index < 0 || index >= filteredResolutions.Count) return;
var r = filteredResolutions[index];
bool isFull = fullscreenToggle != null ? fullscreenToggle.isOn : Screen.fullScreen;
Screen.SetResolution(r.width, r.height, isFull);
PlayerPrefs.SetInt(GameSettings.KeyResolutionWidth, r.width);
PlayerPrefs.SetInt(GameSettings.KeyResolutionHeight, r.height);
}
private void OnVsyncChanged(bool enabled)
{
if (isInitializing) return;
QualitySettings.vSyncCount = enabled ? 1 : 0;
}
private void OnInvertYChanged(bool enabled)
{
if (isInitializing) return;
PlayerPrefs.SetInt("Settings_InvertY", enabled ? 1 : 0);
}
private void OnVolumeChanged(float val)
{
if (isInitializing) return;
PlayerPrefs.SetFloat(GameSettings.KeyMasterVolume, val);
bool isMuted = muteToggle != null && muteToggle.isOn;
if (!isMuted) AudioListener.volume = val;
UpdateVolumeLabel(val, isMuted);
}
private void OnMuteChanged(bool isMuted)
{
if (isInitializing) return;
PlayerPrefs.SetInt(GameSettings.KeyIsMuted, isMuted ? 1 : 0);
float currentVol = volumeSlider != null ? volumeSlider.value : 1.0f;
AudioListener.volume = isMuted ? 0f : currentVol;
UpdateVolumeLabel(currentVol, isMuted);
}
private void UpdateVolumeLabel(float vol, bool muted)
{
if (volumeValueText != null)
{
volumeValueText.text = muted ? "ВЫКЛ" : $"{Mathf.RoundToInt(vol * 100)}%";
}
}
private void OnQualityChanged(int index)
{
if (isInitializing) return;
QualitySettings.SetQualityLevel(index, true);
PlayerPrefs.SetInt(GameSettings.KeyQualityLevel, index);
}
private void OnFullscreenChanged(bool isFullscreen)
{
if (isInitializing) return;
Screen.fullScreen = isFullscreen;
PlayerPrefs.SetInt(GameSettings.KeyFullscreen, isFullscreen ? 1 : 0);
}
private void OnSensitivityChanged(float val)
{
if (isInitializing) return;
PlayerPrefs.SetFloat(GameSettings.KeyMouseSensitivity, val);
UpdateSensitivityLabel(val);
}
private void UpdateSensitivityLabel(float val)
{
if (sensitivityValueText != null)
{
sensitivityValueText.text = $"{val:F1}x";
}
}
private string TranslateQuality(string q)
{
switch (q.ToLower())
{
case "very low": return "Очень низкое";
case "low": return "Низкое";
case "medium": return "Среднее";
case "high": return "Высокое";
case "very high": return "Очень высокое";
case "ultra": return "Ультра";
default: return q;
}
}
}