Update Audio

This commit is contained in:
2026-04-30 17:47:29 +07:00
parent 4709fa0c55
commit 56c35ad1c6
157 changed files with 2138 additions and 8 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1f390a3d7b8c9eb49ac7d779c08ef5f5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e54b0675598e3f946be47398a01b918a

View 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);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 35bf1b4a2b113c048874a8a4a3ea18b3

View File

@@ -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()

View File

@@ -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>();
}
}
}

View 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;
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 28373d86c046d8248b3788daaa019217