• SoundManager—声音管理框架
  • GameManager—游戏逻辑管理类
  • 其他


在上篇博文中我介绍了管理的的枚举与单例基类,接下来将进入本系列博客的正题—管理类框架的实现.

SoundManager—声音管理框架

本框架中采用的声音管理框架是一个简单的管理框架,适用于2D或小型项目,因为其播放元是SoundManager物体身上的两个AudioScource组件,所以很难实现大项目那种随着距离声音出现变化的功能.
管理类动态根据音乐名称加载音频文件,音乐文件存储在Resources下的Sounds中.在用户调用播放方法时根据音频名加载音频文件并播放.
静音是通过控制AudioScource组件的mute属性来实现,所以静音时其实音频依旧会播放,取消静音音乐继续播发(总感觉的如果重新播放怪怪的,需要这方面需求的同学可以自己改)

SoundManager.cs

using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

/// <summary>
/// 声音管理类
/// 针对于只需要播放简单音效的游戏
/// 可以播放背景音乐与音效
/// </summary>
public class SoundManager : Singleton<SoundManager>
{

    #region 数据成员
    //音效文件加载路径
    public string ResourceDir = "Sounds";
    //背景音乐播放组件
    private AudioSource m_bgSound;
    //音效播放组件
    private AudioSource m_effectSound;
    //静音管理
    private bool mute = false;
    public bool Mute
    {
        get
        {
            return mute;
        }

        set
        {
            m_bgSound.mute = value;
            m_effectSound.mute = value;
            mute = value;
        }
    }
    //音乐大小
    public float BgVolume
    {
        get { return m_bgSound.volume; }
        set { m_bgSound.volume = value; }
    }
    //音效大小
    public float EffectVolume
    {
        get { return m_effectSound.volume; }
        set { m_effectSound.volume = value; }
    }


    #endregion

    /// <summary>
    /// 在Awake中添加两个音频播放器并初始化
    /// </summary>
    protected override void Awake()
    {
        base.Awake();

        m_bgSound = this.gameObject.AddComponent<AudioSource>();
        m_bgSound.playOnAwake = false;
        m_bgSound.loop = true;

        m_effectSound = this.gameObject.AddComponent<AudioSource>();
        m_effectSound.playOnAwake = false;
    }

    /// <summary>
    /// 播放BGM
    /// </summary>
    /// <param name="audioName"></param>
    public void PlayBg(string audioName)
    {
        if (Mute)
            return;
        //当前正在播放的音乐文件
        string oldName;
        if (m_bgSound.clip == null)
            oldName = "";
        else
            oldName = m_bgSound.clip.name;

        if (oldName != audioName)
        {
            //音乐文件路径
            string path;
            if (string.IsNullOrEmpty(ResourceDir))
                path = audioName;
            else
                path = ResourceDir + "/" + audioName;

            //加载音乐
            AudioClip clip = Resources.Load<AudioClip>(path);

            //播放
            if (clip != null)
            {
                m_bgSound.clip = clip;
                m_bgSound.Play();
            }
        }
    }

    /// <summary>
    /// 停止BGM
    /// </summary>
    public void StopBg()
    {
        if (m_bgSound.clip != null)
        {
            m_bgSound.Stop();
            m_bgSound.clip = null;
        }
    }

    /// <summary>
    /// 播放音效
    /// </summary>
    /// <param name="audioName"></param>
    public void PlayEffect(string audioName)
    {
        if (Mute)
            return;
        //路径
        string path;
        if (string.IsNullOrEmpty(ResourceDir))
            path = audioName;
        else
            path = ResourceDir + "/" + audioName;

        //音频
        AudioClip clip = Resources.Load<AudioClip>(path);

        //播放
        m_effectSound.PlayOneShot(clip);
    }

    /// <summary>
    /// 静音方法
    /// </summary>
    public void OnMuteButtonDown()
    {
        Mute = true;
    }

    /// <summary>
    /// 取消静音
    /// </summary>
    public void OnNotMuteButtonDown()
    {
        Mute = false;
    }
}

GameManager—游戏逻辑管理类

游戏管理类时一个提供给玩家拓展的类,如果只有一个场景,可以直接在场景中添加空物体Gamemanager并挂载脚本GameManager脚本,若存在多个脚本可在每个界面创建一个SceneManager脚本(挂载在对应界面的一个空物体上)并让其继承自GameManager.
GameManager中定义一个管理类枚举数组,请在Inspector面板对其赋值,赋值内容为本场景中要实例化的挂载相应管理类的预制体的枚举值.例如在第二个场景中我不需要SoundManager管理类,那么在该场景的场景管理类(继承自GameManager)中不赋值SoundManager即可.
请确保添加在管理类预制体枚举类型中的值在Resources下的ManagerPrefab中存在挂载该管理脚本的预制体.

GameManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

/// <summary>
/// 游戏管理类
/// 若你的游戏中只有一个界面,请使用它进行初始化操作
/// 若游戏中存在多个场景,请创建对应场景的管理类并继承自GameManager,子类需重写Awake方法时需要调用父类的Awake方法
/// </summary>
public class GameManager : Singleton<GameManager>
{
    #region 数据成员
    //设置加载挂在着管理类的预制体的路径
    private static readonly string ManagerPrefabPath = "ManagerPrefab";
    //设置当前页面需要加载的管理类的对应枚举类型
    public List<ManagerType> managerTypes;
    #endregion

    /// <summary>
    /// 根据managerTypes加载挂载对应管理脚本的预制体
    /// </summary>
    protected new virtual void Awake()
    {
        base.Awake();
        foreach (ManagerType type in managerTypes)
        {
            Instantiate(Resources.Load<GameObject>(ManagerPrefabPath + "/" + type.ToString()), new Vector3(0, 0, 0), Quaternion.identity);
        }
    }
}

其他

在下篇博客中,我讲为大家介绍一个对于利用本地文件(.txt .xml .json)存储信息时一个特别重要的管理框架—待修改信息复制框架.