using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; using UnityEngine.UI; public class UIManager : Singleton { [SerializeField] private GameObject menuUI; [SerializeField] private float distanceFromPlayer = 1.5f; [Header("声音设置")] [SerializeField] private Toggle backgroundMusicToggle; [SerializeField] private Toggle narrationToggle; [Header("风格设置")] [SerializeField] private Dropdown visualStyleDropdown; [SerializeField] private Renderer[] floorRenderers; [SerializeField] private Renderer[] wallRenderers; [SerializeField] private Material[] floorMaterials; [SerializeField] private Material[] wallMaterials; [Header("后处理设置")] [SerializeField] private Volume postProcessVolume; [SerializeField] private Slider colorTemperatureSlider; [SerializeField] private Slider exposureSlider; [SerializeField] private Slider saturationSlider; [Header("后处理滑块对应范围")] [SerializeField] private Vector2 colorTemperatureRange = new Vector2(-100f, 100f); [SerializeField] private Vector2 exposureRange = new Vector2(-5f, 5f); [SerializeField] private Vector2 saturationRange = new Vector2(-100f, 100f); private Text colorTemperatureValueText; private Text exposureValueText; private Text saturationValueText; private WhiteBalance whiteBalance; private ColorAdjustments colorAdjustments; protected override void Awake() { base.Awake(); if (Instance != this) { return; } if (menuUI == null) { menuUI = GameObject.Find("MenuUI"); } if (menuUI != null) { menuUI.SetActive(false); } else { Debug.LogError("UIManager:没有找到 MenuUI。", this); } if (backgroundMusicToggle != null) { backgroundMusicToggle.onValueChanged.AddListener(SetBackgroundMusicEnabled); } if (narrationToggle != null) { narrationToggle.onValueChanged.AddListener(SetNarrationEnabled); } if (visualStyleDropdown != null) { visualStyleDropdown.onValueChanged.AddListener(ApplyVisualStyle); } colorTemperatureValueText = FindValueText(colorTemperatureSlider); exposureValueText = FindValueText(exposureSlider); saturationValueText = FindValueText(saturationSlider); if (colorTemperatureSlider != null) { colorTemperatureSlider.onValueChanged.AddListener(ApplyColorTemperature); } if (exposureSlider != null) { exposureSlider.onValueChanged.AddListener(ApplyExposure); } if (saturationSlider != null) { saturationSlider.onValueChanged.AddListener(ApplySaturation); } } private void Start() { if (backgroundMusicToggle != null) { SetBackgroundMusicEnabled(backgroundMusicToggle.isOn); } if (narrationToggle != null) { SetNarrationEnabled(narrationToggle.isOn); } if (visualStyleDropdown != null) { ApplyVisualStyle(visualStyleDropdown.value); } InitializePostProcessing(); SyncSlidersWithPostProcessing(); } private void OnDestroy() { if (backgroundMusicToggle != null) { backgroundMusicToggle.onValueChanged.RemoveListener(SetBackgroundMusicEnabled); } if (narrationToggle != null) { narrationToggle.onValueChanged.RemoveListener(SetNarrationEnabled); } if (visualStyleDropdown != null) { visualStyleDropdown.onValueChanged.RemoveListener(ApplyVisualStyle); } if (colorTemperatureSlider != null) { colorTemperatureSlider.onValueChanged.RemoveListener(ApplyColorTemperature); } if (exposureSlider != null) { exposureSlider.onValueChanged.RemoveListener(ApplyExposure); } if (saturationSlider != null) { saturationSlider.onValueChanged.RemoveListener(ApplySaturation); } } private void LateUpdate() { Transform player = GameManager.Instance.Player; if (menuUI == null || menuUI.activeSelf || player == null) { return; } PlaceMenuInFrontOfPlayer(player); } public void ToggleMenu() { if (menuUI == null) { return; } bool shouldShow = !menuUI.activeSelf; if (shouldShow && GameManager.Instance.Player != null) { PlaceMenuInFrontOfPlayer(GameManager.Instance.Player); } menuUI.SetActive(shouldShow); } private void SetBackgroundMusicEnabled(bool isEnabled) { AudioManager.Instance.SetBackgroundMusicEnabled(isEnabled); } private void SetNarrationEnabled(bool isEnabled) { AudioManager.Instance.SetNarrationEnabled(isEnabled); } private void ApplyVisualStyle(int styleIndex) { ApplyMaterial(floorRenderers, floorMaterials, styleIndex); ApplyMaterial(wallRenderers, wallMaterials, styleIndex); } private void InitializePostProcessing() { if (postProcessVolume == null || postProcessVolume.profile == null) { Debug.LogWarning("UIManager:没有指定可用的后处理 Volume。", this); return; } postProcessVolume.profile.TryGet(out whiteBalance); postProcessVolume.profile.TryGet(out colorAdjustments); } private void ApplyColorTemperature(float value) { float temperature = GetPostProcessValue(colorTemperatureSlider, value, colorTemperatureRange); UpdateValueText(colorTemperatureValueText, temperature); if (whiteBalance != null) { whiteBalance.temperature.overrideState = true; whiteBalance.temperature.value = temperature; } } private void ApplyExposure(float value) { float exposure = GetPostProcessValue(exposureSlider, value, exposureRange); UpdateValueText(exposureValueText, exposure); if (colorAdjustments != null) { colorAdjustments.postExposure.overrideState = true; colorAdjustments.postExposure.value = exposure; } } private void ApplySaturation(float value) { float saturation = GetPostProcessValue(saturationSlider, value, saturationRange); UpdateValueText(saturationValueText, saturation); if (colorAdjustments != null) { colorAdjustments.saturation.overrideState = true; colorAdjustments.saturation.value = saturation; } } private void SyncSlidersWithPostProcessing() { if (colorTemperatureSlider != null && whiteBalance != null) { colorTemperatureSlider.SetValueWithoutNotify( GetSliderValue(colorTemperatureSlider, whiteBalance.temperature.value, colorTemperatureRange)); } if (exposureSlider != null && colorAdjustments != null) { exposureSlider.SetValueWithoutNotify( GetSliderValue(exposureSlider, colorAdjustments.postExposure.value, exposureRange)); } if (saturationSlider != null && colorAdjustments != null) { saturationSlider.SetValueWithoutNotify( GetSliderValue(saturationSlider, colorAdjustments.saturation.value, saturationRange)); } if (colorTemperatureSlider != null) { ApplyColorTemperature(colorTemperatureSlider.value); } if (exposureSlider != null) { ApplyExposure(exposureSlider.value); } if (saturationSlider != null) { ApplySaturation(saturationSlider.value); } } private static float GetPostProcessValue(Slider slider, float sliderValue, Vector2 valueRange) { if (slider == null || Mathf.Approximately(slider.minValue, slider.maxValue)) { return valueRange.x; } float normalizedValue = Mathf.InverseLerp(slider.minValue, slider.maxValue, sliderValue); return Mathf.Lerp(valueRange.x, valueRange.y, normalizedValue); } private static float GetSliderValue(Slider slider, float postProcessValue, Vector2 valueRange) { if (slider == null || Mathf.Approximately(valueRange.x, valueRange.y)) { return 0f; } float normalizedValue = Mathf.InverseLerp(valueRange.x, valueRange.y, postProcessValue); return Mathf.Lerp(slider.minValue, slider.maxValue, normalizedValue); } private static Text FindValueText(Slider slider) { if (slider == null || slider.transform.parent == null) { return null; } Transform parent = slider.transform.parent; Text textAfterSlider = null; foreach (Transform sibling in parent) { Text siblingText = sibling.GetComponent(); if (siblingText == null) { continue; } if (sibling.name.IndexOf("Value", System.StringComparison.OrdinalIgnoreCase) >= 0) { return siblingText; } if (sibling.GetSiblingIndex() > slider.transform.GetSiblingIndex() && textAfterSlider == null) { textAfterSlider = siblingText; } } return textAfterSlider; } private static void UpdateValueText(Text valueText, float value) { if (valueText == null) { return; } valueText.text = value.ToString("0.##"); } private static void ApplyMaterial(Renderer[] renderers, Material[] materials, int styleIndex) { if (renderers == null || materials == null || styleIndex < 0 || styleIndex >= materials.Length || materials[styleIndex] == null) { return; } foreach (Renderer targetRenderer in renderers) { if (targetRenderer != null) { targetRenderer.sharedMaterial = materials[styleIndex]; } } } private void PlaceMenuInFrontOfPlayer(Transform player) { menuUI.transform.position = player.position + player.forward * distanceFromPlayer; menuUI.transform.forward = player.forward; } }