游戏音效脚本添加

1. 音效管理器主脚本

csharp 复制代码
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;

public enum SoundType
{
    // 背景音乐
    BackgroundMusic,
    
    // 游戏音效
    BlockClick,
    BlockMatch,
    BlockDestroy,
    BlockPlace,
    
    // 道具音效
    PowerUpCollect,
    PowerUpUse,
    PowerUpSpecial,
    
    // UI音效
    UIClick,
    UIButtonHover,
    UIOpenMenu,
    UICloseMenu,
    UINotification,
    UISuccess,
    UIFailure,
    
    // 游戏状态音效
    GameStart,
    GameOver,
    LevelComplete,
    ScoreIncrease
}

[System.Serializable]
public class Sound
{
    public SoundType type;
    public AudioClip clip;
    
    [Range(0f, 1f)]
    public float volume = 1f;
    
    [Range(0.1f, 3f)]
    public float pitch = 1f;
    
    public bool loop = false;
    
    [HideInInspector]
    public AudioSource source;
}

public class AudioManager : MonoBehaviour
{
    public static AudioManager Instance { get; private set; }
    
    [Header("音频混合器")]
    public AudioMixer audioMixer;
    
    [Header("音效列表")]
    [SerializeField] private List<Sound> sounds = new List<Sound>();
    
    [Header("音效设置")]
    [SerializeField] private float soundFadeDuration = 1f;
    
    private Dictionary<SoundType, Sound> soundDictionary = new Dictionary<SoundType, Sound>();
    private Sound currentBackgroundMusic;
    private Coroutine fadeCoroutine;
    
    void Awake()
    {
        // 单例模式
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
            return;
        }
        
        InitializeSounds();
        LoadAudioSettings();
    }
    
    void InitializeSounds()
    {
        foreach (Sound sound in sounds)
        {
            AudioSource source = gameObject.AddComponent<AudioSource>();
            source.clip = sound.clip;
            source.volume = sound.volume;
            source.pitch = sound.pitch;
            source.loop = sound.loop;
            
            sound.source = source;
            soundDictionary[sound.type] = sound;
        }
    }
    
    public void PlaySound(SoundType type, bool oneShot = false)
    {
        if (soundDictionary.TryGetValue(type, out Sound sound))
        {
            if (oneShot)
            {
                sound.source.PlayOneShot(sound.clip, sound.volume);
            }
            else
            {
                sound.source.Play();
            }
        }
        else
        {
            Debug.LogWarning($"音效 {type} 未找到!");
        }
    }
    
    public void StopSound(SoundType type)
    {
        if (soundDictionary.TryGetValue(type, out Sound sound))
        {
            sound.source.Stop();
        }
    }
    
    public void PlayBackgroundMusic(SoundType type, bool fade = true)
    {
        if (soundDictionary.TryGetValue(type, out Sound newBackgroundMusic))
        {
            if (fadeCoroutine != null)
            {
                StopCoroutine(fadeCoroutine);
            }
            
            fadeCoroutine = StartCoroutine(FadeBackgroundMusic(newBackgroundMusic, fade));
        }
    }
    
    private IEnumerator FadeBackgroundMusic(Sound newBackgroundMusic, bool fade)
    {
        // 淡出当前背景音乐
        if (currentBackgroundMusic != null && currentBackgroundMusic.source.isPlaying)
        {
            float startVolume = currentBackgroundMusic.source.volume;
            float timer = 0f;
            
            while (timer < soundFadeDuration)
            {
                timer += Time.deltaTime;
                currentBackgroundMusic.source.volume = Mathf.Lerp(startVolume, 0f, timer / soundFadeDuration);
                yield return null;
            }
            
            currentBackgroundMusic.source.Stop();
            currentBackgroundMusic.source.volume = startVolume;
        }
        
        // 播放新的背景音乐
        currentBackgroundMusic = newBackgroundMusic;
        
        if (fade)
        {
            currentBackgroundMusic.source.volume = 0f;
            currentBackgroundMusic.source.Play();
            
            float timer = 0f;
            while (timer < soundFadeDuration)
            {
                timer += Time.deltaTime;
                currentBackgroundMusic.source.volume = Mathf.Lerp(0f, currentBackgroundMusic.volume, timer / soundFadeDuration);
                yield return null;
            }
        }
        else
        {
            currentBackgroundMusic.source.volume = currentBackgroundMusic.volume;
            currentBackgroundMusic.source.Play();
        }
    }
    
    public void SetMasterVolume(float volume)
    {
        audioMixer.SetFloat("MasterVolume", Mathf.Log10(volume) * 20);
        PlayerPrefs.SetFloat("MasterVolume", volume);
    }
    
    public void SetMusicVolume(float volume)
    {
        audioMixer.SetFloat("MusicVolume", Mathf.Log10(volume) * 20);
        PlayerPrefs.SetFloat("MusicVolume", volume);
    }
    
    public void SetSFXVolume(float volume)
    {
        audioMixer.SetFloat("SFXVolume", Mathf.Log10(volume) * 20);
        PlayerPrefs.SetFloat("SFXVolume", volume);
    }
    
    private void LoadAudioSettings()
    {
        // 加载保存的音量设置
        SetMasterVolume(PlayerPrefs.GetFloat("MasterVolume", 1f));
        SetMusicVolume(PlayerPrefs.GetFloat("MusicVolume", 1f));
        SetSFXVolume(PlayerPrefs.GetFloat("SFXVolume", 1f));
    }
    
    // 快捷方法
    public void PlayBlockClick() => PlaySound(SoundType.BlockClick, true);
    public void PlayBlockMatch() => PlaySound(SoundType.BlockMatch, true);
    public void PlayBlockDestroy() => PlaySound(SoundType.BlockDestroy, true);
    public void PlayUIClick() => PlaySound(SoundType.UIClick, true);
    public void PlayPowerUpUse() => PlaySound(SoundType.PowerUpUse, true);
}

2. UI音效触发器脚本

csharp 复制代码
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class UISoundTrigger : MonoBehaviour, IPointerEnterHandler, IPointerClickHandler
{
    [Header("音效设置")]
    [SerializeField] private SoundType clickSound = SoundType.UIClick;
    [SerializeField] private SoundType hoverSound = SoundType.UIButtonHover;
    [SerializeField] private bool enableHoverSound = true;
    
    private Button button;
    private Toggle toggle;
    private Slider slider;
    
    void Start()
    {
        button = GetComponent<Button>();
        toggle = GetComponent<Toggle>();
        slider = GetComponent<Slider>();
        
        // 为UI组件添加声音
        if (button != null)
        {
            button.onClick.AddListener(OnButtonClick);
        }
        
        if (toggle != null)
        {
            toggle.onValueChanged.AddListener(OnToggleValueChanged);
        }
        
        if (slider != null)
        {
            slider.onValueChanged.AddListener(OnSliderValueChanged);
        }
    }
    
    private void OnButtonClick()
    {
        if (AudioManager.Instance != null)
        {
            AudioManager.Instance.PlaySound(clickSound, true);
        }
    }
    
    private void OnToggleValueChanged(bool isOn)
    {
        if (AudioManager.Instance != null && isOn)
        {
            AudioManager.Instance.PlaySound(clickSound, true);
        }
    }
    
    private void OnSliderValueChanged(float value)
    {
        // 可以为滑动条添加特殊音效
        if (AudioManager.Instance != null)
        {
            AudioManager.Instance.PlaySound(SoundType.UIClick, true);
        }
    }
    
    public void OnPointerClick(PointerEventData eventData)
    {
        // 备用点击检测
        if (button == null && toggle == null && slider == null)
        {
            if (AudioManager.Instance != null)
            {
                AudioManager.Instance.PlaySound(clickSound, true);
            }
        }
    }
    
    public void OnPointerEnter(PointerEventData eventData)
    {
        if (enableHoverSound && AudioManager.Instance != null)
        {
            AudioManager.Instance.PlaySound(hoverSound, true);
        }
    }
}

3. 游戏块音效脚本

csharp 复制代码
using UnityEngine;

public class BlockSoundController : MonoBehaviour
{
    [Header("音效设置")]
    [SerializeField] private SoundType clickSound = SoundType.BlockClick;
    [SerializeField] private SoundType matchSound = SoundType.BlockMatch;
    [SerializeField] private SoundType destroySound = SoundType.BlockDestroy;
    [SerializeField] private SoundType placeSound = SoundType.BlockPlace;
    
    [Header("音效触发")]
    [SerializeField] private bool playOnClick = true;
    [SerializeField] private bool playOnDestroy = true;
    
    private Collider blockCollider;
    
    void Start()
    {
        blockCollider = GetComponent<Collider>();
        
        if (blockCollider == null)
        {
            blockCollider = gameObject.AddComponent<BoxCollider>();
        }
    }
    
    void OnMouseDown()
    {
        if (playOnClick && AudioManager.Instance != null)
        {
            AudioManager.Instance.PlaySound(clickSound, true);
        }
    }
    
    void OnDestroy()
    {
        if (playOnDestroy && AudioManager.Instance != null)
        {
            AudioManager.Instance.PlaySound(destroySound, true);
        }
    }
    
    public void PlayMatchSound()
    {
        if (AudioManager.Instance != null)
        {
            AudioManager.Instance.PlaySound(matchSound, true);
        }
    }
    
    public void PlayPlaceSound()
    {
        if (AudioManager.Instance != null)
        {
            AudioManager.Instance.PlaySound(placeSound, true);
        }
    }
}

4. 音效设置UI面板

csharp 复制代码
using UnityEngine;
using UnityEngine.UI;

public class AudioSettingsPanel : MonoBehaviour
{
    [Header("音量控制滑块")]
    [SerializeField] private Slider masterVolumeSlider;
    [SerializeField] private Slider musicVolumeSlider;
    [SerializeField] private Slider sfxVolumeSlider;
    
    [Header("测试按钮")]
    [SerializeField] private Button testSFXButton;
    [SerializeField] private Button testMusicButton;
    
    void Start()
    {
        InitializeSliders();
        SetupTestButtons();
    }
    
    void InitializeSliders()
    {
        if (masterVolumeSlider != null)
        {
            masterVolumeSlider.value = PlayerPrefs.GetFloat("MasterVolume", 1f);
            masterVolumeSlider.onValueChanged.AddListener(OnMasterVolumeChanged);
        }
        
        if (musicVolumeSlider != null)
        {
            musicVolumeSlider.value = PlayerPrefs.GetFloat("MusicVolume", 1f);
            musicVolumeSlider.onValueChanged.AddListener(OnMusicVolumeChanged);
        }
        
        if (sfxVolumeSlider != null)
        {
            sfxVolumeSlider.value = PlayerPrefs.GetFloat("SFXVolume", 1f);
            sfxVolumeSlider.onValueChanged.AddListener(OnSFXVolumeChanged);
        }
    }
    
    void SetupTestButtons()
    {
        if (testSFXButton != null)
        {
            testSFXButton.onClick.AddListener(() => {
                if (AudioManager.Instance != null)
                {
                    AudioManager.Instance.PlaySound(SoundType.UIClick, true);
                }
            });
        }
        
        if (testMusicButton != null)
        {
            testMusicButton.onClick.AddListener(() => {
                if (AudioManager.Instance != null)
                {
                    AudioManager.Instance.PlaySound(SoundType.UISuccess, true);
                }
            });
        }
    }
    
    void OnMasterVolumeChanged(float value)
    {
        if (AudioManager.Instance != null)
        {
            AudioManager.Instance.SetMasterVolume(value);
        }
    }
    
    void OnMusicVolumeChanged(float value)
    {
        if (AudioManager.Instance != null)
        {
            AudioManager.Instance.SetMusicVolume(value);
        }
    }
    
    void OnSFXVolumeChanged(float value)
    {
        if (AudioManager.Instance != null)
        {
            AudioManager.Instance.SetSFXVolume(value);
        }
    }
}

5. 音频混合器设置(AudioMixer)

创建一个AudioMixer并命名为"MainMixer",设置以下参数:

  • MasterVolume (暴露参数)
  • MusicVolume (暴露参数)
  • SFXVolume (暴露参数)

6. 音效文件建议

  1. 背景音乐

    • 游戏配乐:可在pixabay.com的"游戏配乐"分类查找
    • 休闲背景音乐:适合消除类游戏
  2. 方块音效

    • 点击:清脆的"click"或"pop"声
    • 消除:短促的"ding"或"ping"声
    • 放置:轻微的"thud"或"tap"声
  3. UI音效

    • 点击:界面按钮音效
    • 悬停:轻微的"hover"声
    • 通知:短促提示音
  4. 道具音效

    • 收集:悦耳的"collect"声
    • 使用:特殊效果音

7. 使用示例脚本

csharp 复制代码
using UnityEngine;

public class GameController : MonoBehaviour
{
    void Start()
    {
        // 播放背景音乐
        AudioManager.Instance.PlayBackgroundMusic(SoundType.BackgroundMusic, true);
        
        // 游戏开始音效
        AudioManager.Instance.PlaySound(SoundType.GameStart, true);
    }
    
    public void OnBlockMatched()
    {
        // 方块匹配音效
        AudioManager.Instance.PlaySound(SoundType.BlockMatch, true);
        
        // 如果连续匹配,可以播放特殊音效
        if (IsCombo())
        {
            AudioManager.Instance.PlaySound(SoundType.PowerUpSpecial, true);
        }
    }
    
    public void OnPowerUpCollected()
    {
        // 收集道具音效
        AudioManager.Instance.PlaySound(SoundType.PowerUpCollect, true);
    }
    
    public void OnLevelComplete()
    {
        // 停止背景音乐
        AudioManager.Instance.StopSound(SoundType.BackgroundMusic);
        
        // 播放完成音效
        AudioManager.Instance.PlaySound(SoundType.LevelComplete, true);
    }
    
    private bool IsCombo()
    {
        // 判断连击逻辑
        return false;
    }
}

安装步骤:

  1. 创建一个空GameObject,命名为"AudioManager"
  2. 将AudioManager脚本附加到该对象
  3. 在Inspector面板中,为每种SoundType分配对应的AudioClip
  4. 为UI按钮添加UISoundTrigger脚本
  5. 为游戏块添加BlockSoundController脚本
  6. 创建音量设置面板并附加AudioSettingsPanel脚本
相关推荐
JIngJaneIL8 小时前
基于java+ vue畅游游戏销售管理系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot·游戏
顾安r8 小时前
12.17 脚本网页 创意导航
java·linux·前端·游戏·html
zore_c8 小时前
【C语言】贪吃蛇游戏超详解(包含音效、颜色、封装成应用等)
c语言·数据结构·笔记·stm32·游戏·链表
chao1898441 天前
基于C# WinForm实现的仿微信打飞机游戏
游戏·微信·c#
張 ~1 天前
上班好玩的桌面宠物软件游戏
游戏·宠物·桌面宠物游戏·bongo cat
hn小菜鸡1 天前
LeetCode 1306.跳跃游戏III
算法·leetcode·游戏
咕噜企业分发小米1 天前
腾讯云游戏音视频方案如何助力初创公司提升用户粘性?
游戏·音视频·腾讯云
da_vinci_x1 天前
PS 消失点:贴图透视总画歪?无需建模,2D 也能“空间绘图”
游戏·aigc·设计师·贴图·技术美术·游戏美术·关卡设计
gis分享者1 天前
学习threejs,生成复杂3D迷宫游戏
学习·游戏·3d·threejs·cannon·迷宫·cannon-es