主界面添加,许多bug修复。祝贺黑盒1如期开始
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class UIButtonSoundTag : MonoBehaviour
|
||||
{
|
||||
public UIButtonType type = UIButtonType.Default;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d79ee8996aab14d4c83874cff2a311ef
|
||||
@@ -0,0 +1,9 @@
|
||||
public enum UIButtonType
|
||||
{
|
||||
Default,
|
||||
Important,
|
||||
Danger,
|
||||
Tab,
|
||||
Confirm,
|
||||
Back
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b5e54fe0000d5042b67d1b20e4459ab
|
||||
@@ -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>();
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 54b28a52896e6f34688dbfbfbacce12e
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b17299aff05b2649baf94c598a2118c
|
||||
@@ -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:
|
||||
Reference in New Issue
Block a user