Update Audio
This commit is contained in:
8
Assets/Scripts/Audio.meta
Normal file
8
Assets/Scripts/Audio.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f390a3d7b8c9eb49ac7d779c08ef5f5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
48
Assets/Scripts/Audio/AudioDatabase.cs
Normal file
48
Assets/Scripts/Audio/AudioDatabase.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Audio;
|
||||
|
||||
namespace Hallucinate.Audio
|
||||
{
|
||||
[Serializable]
|
||||
public class AudioSample
|
||||
{
|
||||
public string Name;
|
||||
public AudioClip Clip;
|
||||
[Range(0f, 1f)] public float DefaultVolume = 1f;
|
||||
[Range(0.1f, 3f)] public float DefaultPitch = 1f;
|
||||
public AudioMixerGroup MixerGroup;
|
||||
}
|
||||
|
||||
[CreateAssetMenu(fileName = "AudioDatabase", menuName = "Hallucinate/Audio/Audio Database")]
|
||||
public class AudioDatabase : ScriptableObject
|
||||
{
|
||||
[SerializeField] private List<AudioSample> samples = new List<AudioSample>();
|
||||
|
||||
private Dictionary<string, AudioSample> _sampleCache;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_sampleCache = new Dictionary<string, AudioSample>();
|
||||
foreach (var sample in samples)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(sample.Name) && !_sampleCache.ContainsKey(sample.Name))
|
||||
{
|
||||
_sampleCache.Add(sample.Name, sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AudioSample GetSample(string name)
|
||||
{
|
||||
if (_sampleCache == null) Initialize();
|
||||
|
||||
if (_sampleCache.TryGetValue(name, out var sample))
|
||||
{
|
||||
return sample;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Audio/AudioDatabase.cs.meta
Normal file
2
Assets/Scripts/Audio/AudioDatabase.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e54b0675598e3f946be47398a01b918a
|
||||
103
Assets/Scripts/Audio/AudioManager.cs
Normal file
103
Assets/Scripts/Audio/AudioManager.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Audio;
|
||||
|
||||
namespace Hallucinate.Audio
|
||||
{
|
||||
public class AudioManager : MonoBehaviour
|
||||
{
|
||||
public static AudioManager Instance { get; private set; }
|
||||
|
||||
[Header("Settings")]
|
||||
[SerializeField] private AudioDatabase database;
|
||||
[SerializeField] private int poolSize = 20;
|
||||
[SerializeField] private AudioMixerGroup defaultGroup;
|
||||
|
||||
private List<AudioSource> _pool;
|
||||
private int _currentIndex = 0;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
|
||||
InitializePool();
|
||||
if (database != null) database.Initialize();
|
||||
}
|
||||
|
||||
private void InitializePool()
|
||||
{
|
||||
_pool = new List<AudioSource>();
|
||||
for (int i = 0; i < poolSize; i++)
|
||||
{
|
||||
GameObject go = new GameObject($"AudioSource_{i}");
|
||||
go.transform.SetParent(transform);
|
||||
AudioSource source = go.AddComponent<AudioSource>();
|
||||
source.playOnAwake = false;
|
||||
_pool.Add(source);
|
||||
}
|
||||
}
|
||||
|
||||
public void Play(string sampleName, float volumeMult = 1f, float pitchMult = 1f, Vector3? position = null)
|
||||
{
|
||||
if (database == null) return;
|
||||
|
||||
var sample = database.GetSample(sampleName);
|
||||
if (sample == null || sample.Clip == null)
|
||||
{
|
||||
// Silence or log warning if needed
|
||||
return;
|
||||
}
|
||||
|
||||
AudioSource source = GetNextSource();
|
||||
|
||||
// Setup source
|
||||
source.clip = sample.Clip;
|
||||
source.volume = sample.DefaultVolume * volumeMult;
|
||||
source.pitch = sample.DefaultPitch * pitchMult;
|
||||
source.outputAudioMixerGroup = sample.MixerGroup != null ? sample.MixerGroup : defaultGroup;
|
||||
|
||||
if (position.HasValue)
|
||||
{
|
||||
source.spatialBlend = 1f; // 3D
|
||||
source.transform.position = position.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
source.spatialBlend = 0f; // 2D
|
||||
}
|
||||
|
||||
source.Play();
|
||||
}
|
||||
|
||||
private AudioSource GetNextSource()
|
||||
{
|
||||
// Simple round-robin for now, can be improved to find truly "idle" sources
|
||||
AudioSource source = _pool[_currentIndex];
|
||||
_currentIndex = (_currentIndex + 1) % poolSize;
|
||||
return source;
|
||||
}
|
||||
|
||||
public void PlayRandom(string baseName, int variants, float volumeMult = 1f, float pitchMult = 1f)
|
||||
{
|
||||
int rand = UnityEngine.Random.Range(1, variants + 1);
|
||||
Play($"{baseName}-{rand}", volumeMult, pitchMult);
|
||||
}
|
||||
|
||||
// Helper for UI/Global easy access
|
||||
public static void PlayGlobal(string name, float volume = 1f, float pitch = 1f)
|
||||
{
|
||||
if (Instance != null) Instance.Play(name, volume, pitch);
|
||||
}
|
||||
|
||||
public static void PlayRandomGlobal(string baseName, int variants, float volume = 1f, float pitch = 1f)
|
||||
{
|
||||
if (Instance != null) Instance.PlayRandom(baseName, variants, volume, pitch);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Audio/AudioManager.cs.meta
Normal file
2
Assets/Scripts/Audio/AudioManager.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35bf1b4a2b113c048874a8a4a3ea18b3
|
||||
@@ -19,6 +19,9 @@ namespace Hallucinate.UI
|
||||
|
||||
// Đảm bảo ban đầu ẩn hết
|
||||
Hide();
|
||||
|
||||
// Tự động gán âm thanh phản hồi cho các UI elements
|
||||
UIAudioHelper.BindFeedback(root);
|
||||
}
|
||||
|
||||
public virtual void Show()
|
||||
|
||||
@@ -10,6 +10,11 @@ namespace Hallucinate.UI
|
||||
private Label _rank;
|
||||
private ProgressBar _winRateBar;
|
||||
private Label _winRateText;
|
||||
private Button _logoutBtn;
|
||||
|
||||
// Future authentication schema placeholders
|
||||
private string _googleIdPlaceholder = "";
|
||||
private string _avatarUrlPlaceholder = "";
|
||||
|
||||
public override void Initialize(VisualElement uxmlRoot, UIManager manager)
|
||||
{
|
||||
@@ -19,19 +24,60 @@ namespace Hallucinate.UI
|
||||
_rank = root.Q<Label>("Rank");
|
||||
_winRateBar = root.Q<ProgressBar>("WinRateBar");
|
||||
_winRateText = root.Q<Label>("WinRateText");
|
||||
_logoutBtn = root.Q<Button>("LogoutBtn");
|
||||
|
||||
root.Q<Button>("BackBtn").clicked += async () => await uiManager.Pop();
|
||||
|
||||
|
||||
if (_logoutBtn != null)
|
||||
{
|
||||
_logoutBtn.clicked += Logout;
|
||||
}
|
||||
|
||||
LoadProfileData();
|
||||
}
|
||||
|
||||
public override async Task PlayTransitionIn()
|
||||
{
|
||||
LoadProfileData(); // Refresh data every time we show the profile
|
||||
await base.PlayTransitionIn();
|
||||
}
|
||||
|
||||
private void LoadProfileData()
|
||||
{
|
||||
// Dummy data for now
|
||||
_username.text = "GamerPro_2026";
|
||||
// Load saved username or fallback
|
||||
string savedName = PlayerPrefs.GetString("Username", "Unknown Player");
|
||||
_username.text = savedName.ToUpper();
|
||||
|
||||
// Future schema mockup (Google Sign-In)
|
||||
_googleIdPlaceholder = PlayerPrefs.GetString("GoogleID", "NOT_LINKED");
|
||||
_avatarUrlPlaceholder = PlayerPrefs.GetString("AvatarURL", "");
|
||||
|
||||
// Mock progression data for now
|
||||
_rank.text = "DIAMOND II";
|
||||
_winRateBar.value = 72;
|
||||
_winRateText.text = "72%";
|
||||
}
|
||||
|
||||
private async void Logout()
|
||||
{
|
||||
// Clear local save data
|
||||
PlayerPrefs.DeleteKey("Username");
|
||||
PlayerPrefs.DeleteKey("GoogleID");
|
||||
PlayerPrefs.DeleteKey("AvatarURL");
|
||||
PlayerPrefs.Save();
|
||||
|
||||
Debug.Log("[Profile] User logged out.");
|
||||
|
||||
// Disconnect from network if currently running
|
||||
var runner = Object.FindFirstObjectByType<Fusion.NetworkRunner>();
|
||||
if (runner != null && runner.IsRunning)
|
||||
{
|
||||
await runner.Shutdown();
|
||||
}
|
||||
|
||||
// Redirect to Login Screen
|
||||
await uiManager.Push<LoginController>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
111
Assets/Scripts/UI/UIAudioHelper.cs
Normal file
111
Assets/Scripts/UI/UIAudioHelper.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using Hallucinate.Audio;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Hallucinate.UI
|
||||
{
|
||||
public static class UIAudioHelper
|
||||
{
|
||||
public static void BindFeedback(VisualElement root)
|
||||
{
|
||||
if (root == null) return;
|
||||
|
||||
// Bind Buttons (Click & Hover)
|
||||
var buttons = root.Query<Button>().ToList();
|
||||
foreach (var btn in buttons)
|
||||
{
|
||||
btn.RegisterCallback<PointerEnterEvent>(OnButtonHover);
|
||||
btn.RegisterCallback<ClickEvent>(OnButtonClick);
|
||||
}
|
||||
|
||||
// Bind Toggles
|
||||
var toggles = root.Query<Toggle>().ToList();
|
||||
foreach (var tgl in toggles)
|
||||
{
|
||||
tgl.RegisterValueChangedCallback(OnToggleChanged);
|
||||
}
|
||||
|
||||
// Bind TextFields (Focus & Typing)
|
||||
var textFields = root.Query<TextField>().ToList();
|
||||
foreach (var tf in textFields)
|
||||
{
|
||||
tf.RegisterCallback<FocusEvent>(OnTextFieldFocus);
|
||||
tf.RegisterCallback<KeyDownEvent>(OnTextFieldKeyDown, TrickleDown.TrickleDown);
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnButtonHover(PointerEnterEvent evt)
|
||||
{
|
||||
var target = evt.target as VisualElement;
|
||||
string sound = "menuclick"; // Default hover
|
||||
|
||||
string name = target.name.ToLower();
|
||||
if (name.Contains("back")) sound = "menu-back-hover";
|
||||
else if (name.Contains("play")) sound = "menu-play-hover";
|
||||
else if (name.Contains("option") || name.Contains("setting")) sound = "menu-options-hover";
|
||||
else if (name.Contains("exit") || name.Contains("quit")) sound = "menu-exit-hover";
|
||||
|
||||
AudioManager.PlayGlobal(sound, 0.5f, 1.05f);
|
||||
}
|
||||
|
||||
private static void OnButtonClick(ClickEvent evt)
|
||||
{
|
||||
var target = evt.target as VisualElement;
|
||||
string sound = "menuclick"; // Default click
|
||||
|
||||
string name = target.name.ToLower();
|
||||
if (name.Contains("back")) sound = "menu-back-click";
|
||||
else if (name.Contains("close")) sound = "click-close";
|
||||
else if (name.Contains("confirm") || name.Contains("start") || name.Contains("create")) sound = "click-short-confirm";
|
||||
else if (name.Contains("play")) sound = "menu-play-click";
|
||||
else if (name.Contains("option") || name.Contains("setting")) sound = "menu-options-click";
|
||||
else if (name.Contains("exit") || name.Contains("quit")) sound = "menu-exit-click";
|
||||
else if (name.Contains("retry") || name.Contains("restart")) sound = "pause-retry-click";
|
||||
|
||||
float randomPitch = Random.Range(0.98f, 1.02f);
|
||||
AudioManager.PlayGlobal(sound, 1f, randomPitch);
|
||||
}
|
||||
|
||||
private static void OnToggleChanged(ChangeEvent<bool> evt)
|
||||
{
|
||||
string sound = evt.newValue ? "check-on" : "check-off";
|
||||
AudioManager.PlayGlobal(sound, 0.8f);
|
||||
}
|
||||
|
||||
private static void OnTextFieldFocus(FocusEvent evt)
|
||||
{
|
||||
AudioManager.PlayGlobal("UI_Focus", 0.6f);
|
||||
}
|
||||
|
||||
private static void OnTextFieldKeyDown(KeyDownEvent evt)
|
||||
{
|
||||
// Osu style typing feedback
|
||||
switch (evt.keyCode)
|
||||
{
|
||||
case KeyCode.Return:
|
||||
case KeyCode.KeypadEnter:
|
||||
AudioManager.PlayGlobal("key-confirm", 0.8f);
|
||||
break;
|
||||
case KeyCode.Backspace:
|
||||
case KeyCode.Delete:
|
||||
AudioManager.PlayGlobal("key-delete", 0.7f);
|
||||
break;
|
||||
case KeyCode.Space:
|
||||
case KeyCode.CapsLock:
|
||||
AudioManager.PlayGlobal("key-caps", 0.7f);
|
||||
break;
|
||||
case KeyCode.UpArrow:
|
||||
case KeyCode.DownArrow:
|
||||
case KeyCode.LeftArrow:
|
||||
case KeyCode.RightArrow:
|
||||
AudioManager.PlayGlobal("key-movement", 0.6f);
|
||||
break;
|
||||
default:
|
||||
// Play random variation for normal keys (key-press-1 to 4)
|
||||
AudioManager.PlayRandomGlobal("key-press", 4, 0.5f, Random.Range(0.95f, 1.1f));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/UI/UIAudioHelper.cs.meta
Normal file
2
Assets/Scripts/UI/UIAudioHelper.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 28373d86c046d8248b3788daaa019217
|
||||
Reference in New Issue
Block a user