主界面添加,许多bug修复。祝贺黑盒1如期开始

This commit is contained in:
FloatGaming
2026-03-02 04:34:13 +08:00
parent e11cc1da7a
commit 3c1d263ef1
308 changed files with 59216 additions and 32756 deletions
+15
View File
@@ -0,0 +1,15 @@
using UnityEngine;
using UnityEngine.UI;
[DefaultExecutionOrder(-100)]
public class UIAutoRegisterSound : MonoBehaviour
{
void Awake()
{
// Register the entire hierarchy of this prefab
UISystemBootstrap.RegisterHierarchy(gameObject);
// Remove this component as its job is done
Destroy(this);
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 76ce63b908338a84c8a3aa071b90c46b
+112
View File
@@ -0,0 +1,112 @@
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using DG.Tweening;
public class UIButtonInteraction :
MonoBehaviour,
IPointerEnterHandler,
IPointerClickHandler
{
private UIButtonType type = UIButtonType.Default;
private Selectable selectable;
[Header("Animation")]
[SerializeField] private float clickScale = 0.95f;
[SerializeField] private float duration = 0.1f;
[SerializeField] private Ease ease = Ease.OutQuad;
private Vector3 originalScale;
private Tween scaleTween;
void Awake()
{
originalScale = transform.localScale;
selectable = GetComponent<Selectable>();
UIButtonSoundTag tag = GetComponent<UIButtonSoundTag>();
if (tag != null)
type = tag.type;
// Special handling for different types of Selectables
if (selectable is Button button)
{
button.onClick.AddListener(OnButtonClicked);
}
else if (selectable is Toggle toggle)
{
toggle.onValueChanged.AddListener(OnToggleChanged);
}
else if (selectable is Slider slider)
{
slider.onValueChanged.AddListener(OnSliderChanged);
}
else if (selectable is Dropdown dropdown)
{
dropdown.onValueChanged.AddListener(OnDropdownChanged);
}
else if (selectable is TMPro.TMP_Dropdown tmpDropdown)
{
tmpDropdown.onValueChanged.AddListener(OnDropdownChanged);
}
}
private void OnButtonClicked()
{
if (selectable != null && !selectable.interactable) return;
UISoundRouter.Instance?.PlayClick(type);
PlayClickAnimation();
}
private void OnToggleChanged(bool isOn)
{
if (selectable != null && !selectable.interactable) return;
UISoundRouter.Instance?.PlayClick(type);
}
private void OnDropdownChanged(int value)
{
if (selectable != null && !selectable.interactable) return;
UISoundRouter.Instance?.PlayClick(type);
}
private void OnSliderChanged(float value)
{
// Sliders usually don't play sound on every value change
}
public void OnPointerEnter(PointerEventData eventData)
{
if (selectable != null && !selectable.interactable) return;
UISoundRouter.Instance?.PlayHover(type);
}
public void OnPointerClick(PointerEventData eventData)
{
// If it's a Button, Toggle or Dropdown, we already play sound in their specific events
if (selectable is Button || selectable is Toggle || selectable is Dropdown || selectable is TMPro.TMP_Dropdown) return;
if (selectable != null && !selectable.interactable) return;
UISoundRouter.Instance?.PlayClick(type);
PlayClickAnimation();
}
void PlayClickAnimation()
{
scaleTween?.Kill();
transform.localScale = originalScale;
scaleTween = transform
.DOScale(originalScale * clickScale, duration)
.SetEase(ease)
.SetUpdate(true)
.OnComplete(() =>
{
transform
.DOScale(originalScale, duration)
.SetEase(ease)
.SetUpdate(true);
});
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 03ac2292f9fa16e4a9bf75087f11292f
+6
View File
@@ -0,0 +1,6 @@
using UnityEngine;
public class UIButtonSoundTag : MonoBehaviour
{
public UIButtonType type = UIButtonType.Default;
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: d79ee8996aab14d4c83874cff2a311ef
+9
View File
@@ -0,0 +1,9 @@
public enum UIButtonType
{
Default,
Important,
Danger,
Tab,
Confirm,
Back
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2b5e54fe0000d5042b67d1b20e4459ab
+19
View File
@@ -0,0 +1,19 @@
using UnityEngine;
using UnityEngine.Audio;
using System.Collections.Generic;
[CreateAssetMenu(fileName = "UISoundConfig", menuName = "UI/UISoundConfig")]
public class UISoundConfig : ScriptableObject
{
public AudioMixerGroup outputGroup;
[System.Serializable]
public class ButtonSoundEntry
{
public UIButtonType type;
public AudioClip hoverClip;
public AudioClip clickClip;
}
public List<ButtonSoundEntry> soundTable = new List<ButtonSoundEntry>();
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 54b28a52896e6f34688dbfbfbacce12e
+117
View File
@@ -0,0 +1,117 @@
using UnityEngine;
using System.Collections.Generic;
public class UISoundRouter : MonoBehaviour
{
public static UISoundRouter Instance;
[SerializeField] private UISoundConfig soundConfig;
private Dictionary<UIButtonType, UISoundConfig.ButtonSoundEntry> lookup;
private AudioSource audioSource;
private float lastHoverTime;
private float hoverCooldown = 0.1f;
private float lastClickTime;
private float clickCooldown = 0.1f;
void Awake()
{
if (Instance != null)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
audioSource = gameObject.AddComponent<AudioSource>();
audioSource.playOnAwake = false;
// 限制最大并发声音数量,防止音频叠加导致的音量过大
audioSource.priority = 128;
BuildLookup();
}
public void SetConfig(UISoundConfig config)
{
soundConfig = config;
if (soundConfig != null && audioSource != null)
{
audioSource.outputAudioMixerGroup = soundConfig.outputGroup;
}
BuildLookup();
}
void BuildLookup()
{
lookup = new Dictionary<UIButtonType, UISoundConfig.ButtonSoundEntry>();
if (soundConfig == null)
{
Debug.LogWarning("[UISoundRouter] SoundConfig is null! Cannot build lookup.");
return;
}
Debug.Log($"[UISoundRouter] Building lookup for {soundConfig.name} with {soundConfig.soundTable.Count} entries.");
foreach (var entry in soundConfig.soundTable)
{
lookup[entry.type] = entry;
Debug.Log($"[UISoundRouter] Registered sound for {entry.type}: Hover={entry.hoverClip?.name}, Click={entry.clickClip?.name}");
}
}
public void PlayHover(UIButtonType type)
{
if (Time.unscaledTime - lastHoverTime < hoverCooldown)
return;
lastHoverTime = Time.unscaledTime;
if (lookup != null && lookup.TryGetValue(type, out var entry))
{
if (entry.hoverClip != null)
{
// 使用较小的音量播放悬停音效,减少叠加感
audioSource.PlayOneShot(entry.hoverClip, 0.7f);
}
else
{
Debug.LogWarning($"[UISoundRouter] Hover clip is null for type {type}");
}
}
else
{
Debug.LogWarning($"[UISoundRouter] No entry found for type {type} in lookup.");
}
}
public void PlayClick(UIButtonType type)
{
if (Time.unscaledTime - lastClickTime < clickCooldown)
return;
lastClickTime = Time.unscaledTime;
Debug.Log($"[UISoundRouter] PlayClick called for type: {type}");
if (lookup != null && lookup.TryGetValue(type, out var entry))
{
if (entry.clickClip != null)
{
Debug.Log($"[UISoundRouter] Playing click clip: {entry.clickClip.name}");
audioSource.PlayOneShot(entry.clickClip, 1.0f);
}
else
{
Debug.LogWarning($"[UISoundRouter] Click clip is null for type {type}");
}
}
else
{
Debug.LogWarning($"[UISoundRouter] No entry found for type {type} in lookup.");
}
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4b17299aff05b2649baf94c598a2118c
+78
View File
@@ -0,0 +1,78 @@
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public static class UISystemBootstrap
{
private const string defaultConfigPath = "UISoundConfig_Default";
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
static void Init()
{
CreateRouterIfNeeded();
RegisterAll();
SceneManager.sceneLoaded += OnSceneLoaded;
}
static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
RegisterAll();
}
static void CreateRouterIfNeeded()
{
UISoundRouter router;
if (UISoundRouter.Instance != null)
{
router = UISoundRouter.Instance;
}
else
{
GameObject go = new GameObject("UISoundRouter");
router = go.AddComponent<UISoundRouter>();
Object.DontDestroyOnLoad(go);
}
var config = Resources.Load<UISoundConfig>(defaultConfigPath);
if (config != null)
{
router.SetConfig(config);
}
else
{
Debug.LogWarning("UISoundConfig not found in Resources at: " + defaultConfigPath);
}
}
public static void RegisterAll()
{
Debug.Log("RegisterButtons Called");
// Find all Selectable objects (includes Button, Toggle, Slider, etc.)
Selectable[] selectables = Object.FindObjectsOfType<Selectable>(true);
foreach (var sel in selectables)
{
Register(sel);
}
}
public static void RegisterHierarchy(GameObject root)
{
if (root == null) return;
Selectable[] selectables = root.GetComponentsInChildren<Selectable>(true);
foreach (var sel in selectables)
{
Register(sel);
}
}
public static void Register(Selectable sel)
{
if (sel == null) return;
if (sel.GetComponent<UIButtonInteraction>() == null)
{
sel.gameObject.AddComponent<UIButtonInteraction>();
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7c4ef17a6597e4e438e8ae02ba20545c
Binary file not shown.
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 279809e51eb0aec4b91d05c7f3a4cac3
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 8c8b9025c3f080c43af649e1b1dab9f7
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant: