2014-07-29 19:39:49 HeBiReChenAi 阅读数 3268
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

声音渐变,主要是一个声音结构体,一个迭代器,然后去使用它,很方便。
using UnityEngine;
using System.Collections;

//声音结构点//
public struct AudioNode
{
     public AudioSource audioSource;          //声音池//
     public int volumeAdd;                    //声音变化,+1则递增,-1则递减//
     public float durationTime;               //渐变时间//
    
     //初始化构造函数//
     public AudioNode(GameObject obj,AudioClip m_clip,float m_initVolume,int m_volumeAdd,float m_durationTime)
     {
          this.audioSource =obj.AddComponent<AudioSource>();
          this.audioSource.playOnAwake = false;
          this.audioSource.volume = m_initVolume;
          this.audioSource.clip = m_clip;
          this.volumeAdd = m_volumeAdd;
          this.durationTime = m_durationTime;
     }
}

public class SoundControl : MonoBehaviour
{
    
     public AudioClip clip;
     void Start ()
     {
          AudioNode audioNode=new AudioNode(gameObject,clip,0,1,4);
          StartCoroutine("AudioSourceVolume",audioNode);
     }
     #endregion
    
     //声音渐变迭代器//
     IEnumerator AudioSourceVolume(AudioNode audioNode)
     {
          float initVolume = audioNode.audioSource.volume;
          float preTime = 1.0f/audioNode.durationTime;
          if (!audioNode.audioSource.isPlaying) audioNode.audioSource.Play();
          while(true)
          {
               initVolume += audioNode.volumeAdd * Time.deltaTime *preTime;
               if (initVolume >1 || initVolume <0)
               {
                    initVolume = Mathf.Clamp01(initVolume);
                    audioNode.audioSource.volume = initVolume;
                    if (initVolume ==0) audioNode.audioSource.Stop();
                    break;
               }else
               {
                    audioNode.audioSource.volume = initVolume;
               }
               yield return 1;
          }
     }
}

只要结构体设为共有,调用的脚本中协商迭代器就可以调用了。。。。
2017-12-14 18:20:11 YongshuangZhao 阅读数 1788
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

声音和音效在一个项目中是不可缺少的一部分,如下我将带领大家在Unity3D中实现一个简单的声音管理系统。功能如下:

1.利用对象池生成AudioSource对象;(对对象池不了解的童鞋,戳这里http://blog.csdn.net/YongshuangZhao/article/details/78462604

2.开放一个统一的AudioMgr接口实现声音音量和开关的控制;

3.AduioMgr可跨场景使用。

代码如下:

AudioMgr管理声音类

所以声音都由此类生成

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

//声音对象池
public class AudioObjectPool{  
	//要生成的对象池预设  
	private GameObject prefab;  
	//对象池列表  
	private List<GameObject> pool;  
	//构造函数  
	public AudioObjectPool(GameObject prefab, int initialSize) {  
		this.prefab = prefab;  
		this.pool = new List<GameObject>();  
		for (int i = 0; i < initialSize; i++) {  
			AlllocateInstance();  
		}  
	}  
	// 获取实例    
	public GameObject GetInstance() {  
		if (pool.Count == 0) {  
			AlllocateInstance();  
		}  
		GameObject instance = pool[0];  
		pool.RemoveAt(0);  
		instance.SetActive(true);  
		return instance;  
	}  
	// 释放实例  
	public void ReleaseInstance(GameObject instance) {  
		instance.SetActive(false);
		pool.Add(instance);  
	}  
	// 生成本地实例  
	private GameObject AlllocateInstance() {  
		GameObject instance = (GameObject) GameObject.Instantiate(prefab);
		instance.transform.SetParent (AudioMgr._instance.transform);
		instance.SetActive(false);  
		pool.Add(instance);  
		return instance;  
	}  
}

public class AudioMgr : MonoBehaviour
{
    //单例模式
	public static AudioMgr _instance;

    //audioClip列表
    public List<AudioClip> audioList;
	//初始声音预设数量
	public int initAudioPrefabCount=5;
	//记录静音前的音量大小
	[HideInInspector]
	public float tempVolume = 0;
	//是否静音
	private bool isMute = false;
	public bool IsMute {
		set{
			isMute = value;
			if (isMute) {
				tempVolume = AudioListener.volume;
				AudioListener.volume = 0;
			} else {
				AudioListener.volume = tempVolume;
			}
		}
		private get{ return isMute; }
	}

    //声音大小系数
	private float volumeScale = 1;
	public float VolumeScale{
		set{
			volumeScale = Mathf.Clamp01 (value);
			if (!IsMute) {
				AudioListener.volume = value;
			}
		}
		private get{
			return volumeScale;
		}
	}
	//audio字典
	private Dictionary<string, AudioClip> audioDic = new Dictionary<string, AudioClip>();
	//声音对象池
	private AudioObjectPool audioObjectPool;

    void Awake()
    {
        _instance = this;
		DontDestroyOnLoad (this);
    }

    void Start()
	{
		SceneManager.sceneUnloaded += scene => {
			StopAllCoroutines ();
			for (int i = 0; i < transform.childCount; i++) {
				if (transform.GetChild(i).hideFlags != HideFlags.HideInHierarchy) {
					InitAudioSource(transform.GetChild(i).GetComponent<AudioSource> ());
					audioObjectPool.ReleaseInstance (transform.GetChild(i).gameObject);
				}
			}
		};
		GameObject audioPrefab = new GameObject("AudioObjectPool");
		audioPrefab.AddComponent<AudioSource>();
		audioPrefab.GetComponent<AudioSource> ().playOnAwake = false;
		audioObjectPool = new AudioObjectPool (audioPrefab, initAudioPrefabCount);
		audioPrefab.hideFlags = HideFlags.HideInHierarchy;
		audioPrefab.transform.SetParent(this.transform);

        foreach (AudioClip ac in audioList)
        {
            audioDic.Add(ac.name, ac);
		}
    }
	//暂停播放
	public void PauseAudio(AudioSource audioSource){
		audioSource.Pause ();
	}
	//继续播放
	public void ResumeAudio(AudioSource audioSource){
		audioSource.UnPause ();
	}
    //停止播放
    public void StopAudio(AudioSource audioSource)
    {
        audioSource.Stop();
    }
    //播放声音
	public void PlayAudio(AudioSource audioSource, string audioName,float volume=1, bool isLoop = false)
    {
		if (IsMute)
        {
            return;
        }
        AudioClip audioClip;
        if (audioDic.TryGetValue(audioName, out audioClip))
        {
            audioSource.loop = isLoop;
            audioSource.clip = audioClip;
			audioSource.volume = volume;
            if (audioSource.isPlaying)
            {
                audioSource.Stop();
            }
            audioSource.Play();
        }
    }
	public void PlayAudio(Vector3 audioPos, string audioName,float volume=1, bool isLoop = false)
    {
		if (IsMute)
        {
            return;
        }
        AudioClip audioClip;
        if (audioDic.TryGetValue(audioName, out audioClip))
        {
			GameObject audioGo = audioObjectPool.GetInstance();
            audioGo.transform.position = audioPos;
			audioGo.name = audioName;
            AudioSource audioSource = audioGo.GetComponent<AudioSource>();
            audioSource.clip = audioClip;
			audioSource.volume = volume;
            audioSource.loop = isLoop;
			audioSource.Play();
			StartCoroutine(DestroyAudioGo(audioSource, audioClip.length));
        }
    }
	//初始化AudioSource
	private void InitAudioSource(AudioSource audioSource){
		if (audioSource == null) {
			return;
		}
		if (audioSource.isPlaying) {
			audioSource.Stop ();
		}
		audioSource.playOnAwake = false;
		audioSource.loop = false;
		audioSource.volume = 1;
		audioSource.clip = null;
		audioSource.name = "AudioObjectPool";
	}
    //销毁声音
	IEnumerator DestroyAudioGo(AudioSource audioSource, float delayTime)
    {
		yield return new WaitForSeconds (delayTime);
		InitAudioSource (audioSource);
		audioObjectPool.ReleaseInstance (audioSource.gameObject);
    }
	void Destroy(){
		StopAllCoroutines ();
	}
}
客户端

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class AudioUI : MonoBehaviour {
	public static AudioUI _instance;

	//音量大小
	private Slider slider;
	//声音开关
	private Toggle toggle;

	void Awake(){
		_instance = this;
	}
	void Start(){
		slider = transform.Find ("Slider").GetComponent<Slider> ();
		toggle = transform.Find ("Toggle").GetComponent<Toggle> ();

		slider.onValueChanged.AddListener(
			value=>{
				AudioMgr._instance.VolumeScale=value;
			}
		);
		toggle.onValueChanged.AddListener (
			bState => {
				AudioMgr._instance.IsMute = bState;
			}
		);
	}
	void Update(){
		if (Input.GetMouseButtonDown (0)) {
			AudioMgr._instance.PlayAudio (transform.position, "audio");
		}
	}
}
运行结果如图



2019-02-01 21:50:30 LiChangGG 阅读数 314
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

播放背景音乐、播放提示音、播放音效。成组播放、声音源复用、音量控制、音效播放位置等等。

写差不多了,发现不是自己想要的风格。没完善呢就过时的感觉。先放着吧。。。

#if UNITY_EDITOR
//#define Sirenix_OdinInspector
#endif

#if Sirenix_OdinInspector
using Sirenix.OdinInspector;
#endif
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;

/// <summary>
/// 声音管理器
/// (目前不保证稳定,出现问题可尝试"try{}catch{AudioManager.ForceReset();}")
/// </summary>
public class AudioManager :

#if Sirenix_OdinInspector
    SerializedMonoBehaviour
#else
    MonoBehaviour
#endif
{
    public static AudioManager Instance
    {
        get
        {
            CreatAudioManager();
            return instance;
        }
    }
#if Sirenix_OdinInspector
#elif UNITY_EDITOR
    [Header("注意!不要在面板上修改任何值!面板仅为方便观察"),Space(10)]
#endif
    public const int ID_WHEN_NULL = -1;

    #region 设置项
    /// <summary>
    /// 读取默认配置
    /// </summary>
    private void LoadConfig()
    {
        MuteSound = PlayerPrefs.GetInt("MuteSound") > 0 ? true : false;
        SoundVolume = PlayerPrefs.GetFloat("SoundVolume");
        MuteMusic = PlayerPrefs.GetInt("MuteMusic") > 0 ? true : false;
        MusicVolume = PlayerPrefs.GetFloat("MuteSound");
    }
    private void SaveConfig()
    {
        PlayerPrefs.SetInt("MuteSound", MuteSound ? 1 : 0);
        PlayerPrefs.SetFloat("SoundVolume", SoundVolume);
        PlayerPrefs.SetInt("MuteSound", MuteMusic ? 1 : 0);
        PlayerPrefs.SetFloat("MuteSound", MusicVolume);
        PlayerPrefs.Save();
    }
    /// <summary>
    /// 音效静音
    /// </summary>
    public bool MuteSound
    {
        get
        {
            return muteSound;
        }

        set
        {
            if (muteSound == value)
                return;
            needSave = true;
            saveTime = 0;
            muteSound = value;
            if (!muteSound)
                return;
            for (int i = 0; i < playingAudio.Count; i++)
            {
                if (playingAudio != null
                    && !playingAudio[i].IsMusic)
                {
                    playingAudio[i].Stop(0, true);
                }
            }
        }
    }
    /// <summary>
    /// 音效音量
    /// </summary>
    public float SoundVolume
    {
        get
        {
            return soundVolume;
        }

        set
        {
            if (soundVolume == value)
                return;
            needSave = true;
            saveTime = 0;
            soundVolume = value;
        }
    }
    /// <summary>
    /// 背景音乐静音
    /// </summary>
    public bool MuteMusic
    {
        get
        {
            return muteMusic;
        }

        set
        {
            if (muteMusic == value)
                return;
            needSave = true;
            saveTime = 0;
            muteMusic = value;
            if (!muteMusic)
                return;
            for (int i = 0; i < playingAudio.Count; i++)
            {
                if (playingAudio != null
                    && playingAudio[i].IsMusic)
                {
                    playingAudio[i].Stop(2, false);
                }
            }
        }
    }
    /// <summary>
    /// 背景音乐声音大小
    /// </summary>
    public float MusicVolume
    {
        get
        {
            return musicVolume;
        }

        set
        {
            if (musicVolume == value)
                return;
            needSave = true;
            saveTime = 0;
            musicVolume = value;
        }
    }
    #endregion 设置项

    #region 全局工具
    public void Init()
    {
        idPointer = 0;
        AudioControllerDic.Clear();
        LoadConfig();
        OnInit();
        //PerLoad();
    }
    /// <summary>
    /// 重置
    /// </summary>
    public void ForceReset()
    {
        while (sourceCachePool.Count > 0)
        {
            sourceCachePool.Dequeue().Release();
        }
        playingMusic = null;
        playingBGSound = null;
        for (int i = 0; i < playingAudio.Count; i++)
        {
            if (playingAudio[i] != null)
                playingAudio[i].Release();
        }
        playingAudio.Clear();
        audioClipPool.Clear();

        poolTotalCount = 0;
        audioTotalCount = 0;
        recordTimes = 0;
        lastRecordTime = 0;
        Init();
    }
    /// <summary>
    /// 停止所有声音
    /// </summary>
    public void StopAll()
    {
        for (int i = 0; i < playingAudio.Count; i++)
        {
            if (playingAudio[i] != null)
            {
                playingAudio[i].Stop(1, false);
            }
        }
    }
    /// <summary>
    /// 让某声音控制器停止播放
    /// </summary>
    /// <param name="id">声音控制器ID</param>
    /// <param name="transitionTime">过渡时间</param>
    /// <param name="waitFinished">是否等待播放完成</param>
    public void StopAudio(int id, float transitionTime = 0, bool waitFinished = false)
    {
        if (id == ID_WHEN_NULL)
            return;
        if (!AudioControllerDic.ContainsKey(id))
            return;
        if (AudioControllerDic[id] == null)
            return;
        AudioControllerDic[id].Stop(transitionTime, waitFinished);
    }
    #endregion 全局工具

    #region 背景音乐相关接口
    /// <summary>
    /// 播放背景音乐
    /// </summary>
    /// <param name="clipName">音频文件名</param>
    /// <param name="transitionTime">过渡时间</param>
    /// <returns>声音控制器ID</returns>
    public int PlayBackGroundMusic(string clipName, float transitionTime = 1)
    {
        if (MuteMusic)
            return ID_WHEN_NULL;

        if (clipName == null)
            return ID_WHEN_NULL;

        if (IsPlayingBGM(clipName))
            return playingMusic.ID;

        if (transitionTime < 0)
            transitionTime = 0;

        if (playingMusic != null)
            playingMusic.Stop(transitionTime, false);

        playingMusic = GetController();
        playingMusic.SetMusic(transitionTime, false, true, GetClip(clipName));
        return playingMusic.ID;
    }
    /// <summary>
    /// 是否正在播放
    /// </summary>
    /// <returns></returns>
    public bool IsPlayingBGM()
    {
        if (MuteMusic)
            return false;
        if (playingMusic == null)
            return false;
        return playingMusic.IsPlaying();
    }
    /// <summary>
    /// 是否正在播放背景音乐
    /// </summary>
    /// <returns></returns>
    public bool IsPlayingBGM(string clipName)
    {
        if (MuteMusic)
            return false;
        if (playingMusic == null)
            return false;
        return playingMusic.IsPlaying(clipName);
    }
    /// <summary>
    /// 停止播放
    /// </summary>
    /// <param name="waitEnd">是否等待播放完成再停止</param>
    public void StopBGM(bool waitEnd = false)
    {
        if (playingMusic == null)
            return;
        playingMusic.Stop(2, waitEnd);
    }
    /// <summary>
    /// 得到当前正在播放的背景音乐
    /// </summary>
    /// <returns></returns>
    public string GetCurrBGM()
    {
        if (MuteMusic)
            return null;
        if (playingMusic == null)
            return null;
        if (!playingMusic.IsPlaying())
            return null;
        if (playingMusic.audioClips == null)
            return null;
        if (playingMusic.CurrIdex >= playingMusic.audioClips.Length)
            return playingMusic.audioClips[0].name;
        return playingMusic.audioClips[playingMusic.CurrIdex].name;
    }

    /// <summary>
    /// 加入背景音乐播放队列
    /// </summary>
    /// <param name="clipName"></param>
    /// <param name="transitionTime"></param>
    public void PlayQueuedBGM(string clipName, float transitionTime = 0)
    {
        if (MuteMusic)
            return;
        /* */
    }

    #endregion 背景音乐相关接口

    #region 音效相关接口
    /// <summary>
    /// 是否正在播放背景音效
    /// </summary>
    /// <returns></returns>
    public bool IsPlayingRandomSound()
    {
        if (MuteSound)
            return false;
        if (playingBGSound == null)
            return false;
        return playingBGSound.IsPlaying();
    }
    /// <summary>
    /// 得到当前正在播放的背景音效
    /// </summary>
    /// <returns></returns>
    public string[] GetCurrRandomSound()
    {
        if (MuteSound)
            return null;
        if (playingBGSound == null)
            return null;
        if (!playingBGSound.IsPlaying())
            return null;
        if (playingBGSound.audioClips == null)
            return null;
        string[] tmp = new string[playingBGSound.audioClips.Length];
        for (int i = 0; i < tmp.Length; i++)
        {
            if (playingBGSound.audioClips[i] != null)
                tmp[i] = playingBGSound.audioClips[i].name;
        }
        return tmp;
    }
    /// <summary>
    /// 播放随机背景音效(2D)
    /// 随机间隔随机播放音效
    /// </summary>
    /// <param name="clipNames">声音片段名,为null不播放</param>
    /// <param name="minInterval">最小播放间隔</param>
    /// <param name="maxInterval">最大播放间隔</param>
    /// <returns>声音控制器ID</returns>
    public int PlayRandomSound(string[] clipNames, float minInterval, float maxInterval)
    {
        if (MuteSound)
            return ID_WHEN_NULL;
        if (playingBGSound != null)
        {
            playingBGSound.Stop(0, true);
        }
        if (clipNames == null || clipNames.Length == 0)
        {
            playingBGSound = null;
            return ID_WHEN_NULL;
        }
        playingBGSound = GetController();

        playingBGSound.SetSound(null, Vector3.zero, 0, true, 1, true, 1, GetClip(clipNames));
        playingBGSound.SetInterval(minInterval, maxInterval);
        return playingBGSound.ID;
    }
    /// <summary>
    /// 播放一个2D音效
    /// 用于播放提示音等
    /// </summary>
    public int PlaySound(string clipName, float volume = 1)
    {
        if (MuteSound)
            return ID_WHEN_NULL;
        if (clipName == null)
            return ID_WHEN_NULL;
        AudioController audioController = GetController();

        audioController.SetSound(null, Vector3.zero, 0, true, 1, true, volume, GetClip(clipName));
        return audioController.ID;
    }
    public int PlaySound(string clipName, Transform target, Vector3 pos, float volume = 1, float pitch = 1)
    {
        if (MuteSound)
            return ID_WHEN_NULL;
        if (clipName == null)
            return ID_WHEN_NULL;
        AudioController audioController = GetController();
        audioController.SetSound(target, pos, 1, false, pitch, false, volume, GetClip(clipName));
        return audioController.ID;
    }

    public int PlaySound(string[] clipName, Transform target, Vector3 pos, float length = 0, bool random = false, float volume = 1, float pitch = 1)
    {
        if (MuteSound)
            return ID_WHEN_NULL;
        if (clipName == null)
            return ID_WHEN_NULL;
        AudioController audioController = GetController();
        audioController.SetSound(target, pos, 1, random, pitch, false, volume, GetClip(clipName));
        if (length > 0)
            audioController.SetRemainingLength(length, 0);
        return audioController.ID;
    }

    #endregion 音效相关接口

    #region 私有成员


    private bool muteSound = false;
    private float soundVolume = 1;
    private bool muteMusic = false;
    private float musicVolume = 1;
    private float saveTime = 0;
    private bool needSave = false;
#if Sirenix_OdinInspector
    [SerializeField, ReadOnly]
#else
    [SerializeField]
#endif
    private Dictionary<int, AudioController> AudioControllerDic = new Dictionary<int, AudioController>();

    private static AudioManager instance;
    private static void CreatAudioManager()
    {
        if (instance == null)
        {
            AudioManager[] audioManagers = FindObjectsOfType<AudioManager>();
            if (audioManagers != null && audioManagers.Length > 0)
            {
                instance = audioManagers[0];
                DontDestroyOnLoad(instance.gameObject);
                if (audioManagers.Length > 1)
                {
                    Debug.Log("场景中存在多余的AudioManager");
                }
            }
            else
            {
                GameObject obj = new GameObject("AudioManager");
                DontDestroyOnLoad(obj);
                instance = obj.AddComponent<AudioManager>();
            }
        }
    }
    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
        }
        OnAwake();
    }

    #region 生命周期
    private void OnAwake()
    {

    }
    private void OnInit()
    {

    }
    private void Update()
    {
        //驱动AudioController
        for (int i = 0; i < playingAudio.Count; i++)
        {
            if (playingAudio[i] == null)
                continue;
            //更新
            playingAudio[i].OnUpdate(Time.deltaTime);

            //判断更新结果
            if (playingAudio[i].IsDestroyed)
            {
                playingAudio[i] = null;
                continue;
            }

            if (playingAudio[i].IsPlayFinished ||
                playingAudio[i].IsReleased)
            {
                Lose(playingAudio[i]);
            }
        }
        //缓存池
        UpdateCache(Time.deltaTime);
        //延迟保存配置项
        if (needSave)
        {
            saveTime += Time.deltaTime;
            if (saveTime > 10)
            {
                SaveConfig();
                needSave = false;
                saveTime = 0;
            }
        }
    }

    #endregion 生命周期

    #region 缓存池
    /*
     * 作用是创建AudioSource、AudioClip,回收AudioSource、AudioClip,减少实例和销毁频率
     * 如果缓存了过多的对象,要定时清理
     */
#if Sirenix_OdinInspector
    [SerializeField, ReadOnly]
#elif UNITY_EDITOR
    [SerializeField]
#endif
    private AudioController playingMusic;//不会有两个背景音乐同时播放
#if Sirenix_OdinInspector
    [SerializeField, ReadOnly]
#elif UNITY_EDITOR
    [SerializeField]
#endif
    private AudioController playingBGSound;
#if Sirenix_OdinInspector
    [SerializeField, ReadOnly]
#elif UNITY_EDITOR
    [SerializeField]
#endif
    private readonly Dictionary<string, AudioClip> audioClipPool = new Dictionary<string, AudioClip>();
    private readonly List<AudioController> playingAudio = new List<AudioController>();
    private readonly Queue<AudioController> sourceCachePool = new Queue<AudioController>();
    /// <summary>
    /// 预加载
    /// </summary>
    private void PerLoad()
    {
        for (int i = 0; i < 5; i++)
        {
            Lose(CreatAudioController());
        }
    }

    private uint poolTotalCount = 0;
    private uint audioTotalCount = 0;
    private uint recordTimes = 0;
    private float lastRecordTime = 0;
    private int idPointer = 0;
    /// <summary>
    /// 这样会不会增多GC?
    /// </summary>
    /// <param name="deltaTime"></param>
    private void UpdateCache(float deltaTime)
    {
        if (Time.realtimeSinceStartup - lastRecordTime < 20)
            return;
        lastRecordTime = Time.realtimeSinceStartup;
        recordTimes++;
        poolTotalCount += (uint)sourceCachePool.Count;
        poolTotalCount += (uint)playingAudio.Count;


        if (sourceCachePool.Count > poolTotalCount / recordTimes * 1.25f)
        {
            int n = sourceCachePool.Count / 4;
            for (int i = 0; i < n; i++)
            {
                sourceCachePool.Dequeue().Release();
            }
        }

        if (playingAudio.Count > audioTotalCount / recordTimes * 1.25f)
        {
            playingAudio.RemoveAll((AudioController a) => { return a == null; });
        }

        if (recordTimes > 15)
        {
            poolTotalCount = 0;
            audioTotalCount = 0;
            recordTimes = 0;
        }
    }
    private AudioController AddPlayingAudioList(AudioController audioController)
    {
        if (playingAudio.Contains(audioController))
            return audioController;
        for (int i = 0; i < playingAudio.Count; i++)
        {
            if (playingAudio == null)
            {
                playingAudio[i] = audioController;
                return audioController;
            }
        }
        playingAudio.Add(audioController);
        return audioController;
    }
    private AudioController GetController()
    {
        if (sourceCachePool.Count == 0)
        {
            return AddPlayingAudioList(CreatAudioController());
        }
        AudioController audioController;
        for (int i = 0; i < sourceCachePool.Count; i++)
        {
            audioController = sourceCachePool.Dequeue();
            if (audioController.IsReleased)//可用?
            {
                return AddPlayingAudioList(audioController);
            }
            sourceCachePool.Enqueue(audioController);
        }
        return AddPlayingAudioList(CreatAudioController());
    }
    private void Lose(AudioController audioController)
    {
        if (playingAudio.Contains(audioController))
            playingAudio.Remove(audioController);

        if (audioController == null ||
            audioController.IsDestroyed)
            return;
        if (!sourceCachePool.Contains(audioController))
            sourceCachePool.Enqueue(audioController);
        audioController.SetDisable();
    }
    private AudioClip GetClip(string cname)
    {
        if (cname == null)
            return null;
        //存在
        if (audioClipPool.ContainsKey(cname) &&
            audioClipPool[cname] != null)
        {
            return audioClipPool[cname];
        }

        //创建成功
        if (CreatAudioClip(cname))
        {
            return audioClipPool[cname];
        }
        //创建失败
        return null;
    }

    private AudioClip[] GetClip(string[] names)
    {
        if (names == null)
            return null;
        //AudioClip[] audioClips = new AudioClip[names.Length];
        Queue<AudioClip> audioClips = new Queue<AudioClip>();
        AudioClip audioClip;
        for (int i = 0; i < names.Length; i++)
        {
            audioClip = GetClip(names[i]);
            if (audioClip != null)
                audioClips.Enqueue(GetClip(names[i]));
        }

        if (audioClips.Count == 0)
            return null;

        return audioClips.ToArray();
    }

    //private void Lose(AudioClip audioClip)
    //{
    //    audioClipPool.Remove(audioClip.name);
    //    Resources.UnloadAsset(audioClip);
    //}
    /// <summary>
    /// 读取音频文件,改变读取方式可修改这里
    /// </summary>
    /// <param name="name"></param>
    /// <returns>是否读取成功</returns>
    private bool CreatAudioClip(string name)
    {
        AudioClip audioClip = Resources.Load<AudioClip>(name);
        if (audioClip == null)
        {
            Debug.LogError("读取音频资源失败:" + name);
            return false;
        }

        if (audioClipPool.ContainsKey(name))
            audioClipPool[name] = audioClip;
        else
            audioClipPool.Add(name, audioClip);

        return true;
    }
    /// <summary>
    /// 默认属性模板,改默认属性在这里
    /// 特性在AudioController.SetXXX()
    /// </summary>
    /// <returns></returns>
    private AudioController CreatAudioController()
    {
        return new AudioController(this);
    }

    #endregion 缓存池

    /// <summary>
    /// 保存必要信息,以及自主控制声音播放
    /// 若以后有多种行为可改为接口编程
    /// </summary>
    [System.Serializable]
    private class AudioController
    {
        /// <summary>
        /// 声音控制器ID
        /// </summary>
        internal readonly int ID;
        /// <summary>
        /// 目标声音源组建
        /// </summary>
#if Sirenix_OdinInspector
        [SerializeField, ReadOnly, GUIColor("BGC")]
#elif UNITY_EDITOR
        [SerializeField]
#endif
        private AudioSource audioSource;


        /// <summary>
        /// 是否正在播放,用于面板显示
        /// </summary>
#if Sirenix_OdinInspector
#elif UNITY_EDITOR
        [SerializeField]
#endif
        private bool playing = false;
#if UNITY_EDITOR
        /// <summary>
        /// 用于限制面板显示播放进度的最大值和最小值
        /// </summary>
        private float maxProgress = 1;
        /// <summary>
        /// 播放进度,用于面板显示
        /// </summary>
#endif
#if Sirenix_OdinInspector
        private Color BGC { get { return playing ? Color.green : Color.red; } set { } }
        [SerializeField, ReadOnly, PropertyRange(0, "maxProgress"), GUIColor("BGC")]
        private float progress = 0;
#elif UNITY_EDITOR
        [SerializeField]
        private float progress = 0;
#endif

        /// <summary>
        /// 当前音频片段结束时间
        /// </summary>
        private float endTime;
        /// <summary>
        /// 定时停止播放
        /// </summary>
        private float stopTime = 0;
        /// <summary>
        /// 待播音频
        /// </summary>
        internal AudioClip[] audioClips { get; private set; }
        /// <summary>
        /// 追随目标
        /// </summary>
        private Transform target;
        /// <summary>
        /// 坐标及偏移
        /// </summary>
        private Vector3 pos;
        /// <summary>
        /// 是否随机
        /// </summary>
        private bool random = false;
        /// <summary>
        /// 是否循环
        /// </summary>
        private bool loop = false;
        /// <summary>
        /// 为真这逐渐停止播放
        /// </summary>
        private bool stoping = false;
        /// <summary>
        /// 渐入渐出用的
        /// </summary>
        private float volumescale = 0;

        #region AudioSource属性
        internal float minDistance
        {
            get { return audioSource.minDistance; }
            set { audioSource.minDistance = value; }
        }
        internal float maxDistance
        {
            get { return audioSource.maxDistance; }
            set { audioSource.maxDistance = value; }
        }
        internal float spatialBlend
        {
            get { return audioSource.spatialBlend; }
            set { audioSource.spatialBlend = value; }
        }
        internal float pitch
        {
            get { return audioSource.pitch; }
            set { audioSource.pitch = value; }
        }
        internal bool mute
        {
            get { return audioSource.mute; }
            set { audioSource.mute = value; }
        }
        #endregion AudioSource属性

        internal AudioController(AudioManager audioManager)
        {
            ID = audioManager.idPointer++;
            audioManager.AudioControllerDic.Add(ID, this);
            IsPlayFinished = false;
            IsDestroyed = false;
            audioSource = new GameObject("AudioPlayer").AddComponent<AudioSource>();
            audioSource.transform.SetParent(instance.transform, false);
            audioSource.playOnAwake = false;
            audioSource.loop = false;
        }
        /// <summary>
        /// 当前正在播放的几个音频
        /// </summary>
        internal int CurrIdex { get; private set; }

        /// <summary>
        /// 是否播放完成
        /// </summary>
        internal bool IsPlayFinished { get; private set; }
        /// <summary>
        /// 是否被销毁
        /// </summary>
        internal bool IsDestroyed { get; private set; }
        /// <summary>
        /// 是背景音乐还是音效
        /// </summary>
        internal bool IsMusic { get; private set; }
        /// <summary>
        /// 是否不再使用(不再播放,没有渐变,不需要再更新。可以重新利用了)
        /// </summary>
        internal bool IsReleased { get; private set; }
        /// <summary>
        /// 过渡时间
        /// </summary>
        internal float TransitionTime { get; private set; }
        /// <summary>
        /// 音量参数,不是实际音量,是传入的音量
        /// </summary>
        internal float Volume { get; private set; }
        /// <summary>
        /// 最小随机间隔
        /// </summary>
        internal float MinInterval { get; private set; }
        /// <summary>
        /// 最大随机间隔
        /// </summary>
        internal float MaxInterval { get; private set; }
        /// <summary>
        /// 开始播放的时间
        /// </summary>
        internal float StartTime { get; private set; }

        /// <summary>
        /// 播放背景音乐(背景音乐模板)
        /// </summary>
        /// <param name="transitionTime"></param>
        /// <param name="audioClips"></param>
        internal void SetMusic(float transitionTime, bool random, bool loop, params AudioClip[] audioClips)
        {
            //判断这些音频是否可用
            if (audioClips == null || audioClips.Length == 0 || audioClips[0] == null)
            {
                audioSource.Stop();
                IsPlayFinished = true;
                IsReleased = true;
                return;
            }

            //初始化数值
            stopTime = 0;
            IsPlayFinished = false;
            IsReleased = false;
            target = null;
            volumescale = 0;
            Volume = 1;
            StartTime = Time.realtimeSinceStartup;
            IsMusic = true;
            audioSource.loop = true;
            loop = true;
            stoping = false;
            pitch = 1;
            audioSource.spatialBlend = 0;
            audioSource.loop = true;
            pos = Vector3.zero;
            CurrIdex = 0;

#if UNITY_EDITOR
            //面板显示进度
            endTime = 0;
            for (int i = 0; i < audioClips.Length; i++)
            {
                if (audioClips[i] != null)
                {
                    endTime += audioClips[i].length;
                }
            }
#if Sirenix_OdinInspector
            maxProgress = endTime;
#endif
#endif
            //赋值
            TransitionTime = transitionTime;
            if (audioClips.Length > 1)
                this.random = random;
            else
                this.random = false;
            if (random)
                this.loop = true;
            else
                this.loop = loop;
            this.audioClips = audioClips;


            Play();
        }
        /// <summary>
        /// 播放音效(音效模板)
        /// </summary>
        /// <param name="target">音效跟谁目标</param>
        /// <param name="pos">偏移或世界坐标</param>
        /// <param name="space3d">2D或3D声音(0~1)</param>
        /// <param name="random">是否随机播放,若随机,则一定循环</param>
        /// <param name="pitch">音调</param>
        /// <param name="loop">是否循环,若随机,则一定循环</param>
        /// <param name="audioClips">音频文件</param>
        internal void SetSound(Transform target, Vector3 pos, float space3d, bool random, float pitch, bool loop, float volume, params AudioClip[] audioClips)
        {
            //判断这些音频是否可用
            if (audioClips == null || audioClips.Length == 0 || audioClips[0] == null)
            {
                audioSource.Stop();
                IsPlayFinished = true;
                IsReleased = true;
                return;
            }

            //初始化数值
            SetInterval(0, 0);
            stopTime = 0;
            IsPlayFinished = false;
            IsReleased = false;
            volumescale = 0;
            stoping = false;
            TransitionTime = 0;
            IsMusic = false;
            CurrIdex = -1;
            StartTime = Time.realtimeSinceStartup;
            this.target = target;
            this.pos = pos;
            audioSource.loop = false;

#if UNITY_EDITOR
            //面板显示进度
            endTime = 0;
            for (int i = 0; i < audioClips.Length; i++)
            {
                if (audioClips[i] != null)
                {
                    endTime += audioClips[i].length;
                }
            }
#if Sirenix_OdinInspector
            maxProgress = endTime;
#endif
#endif
            //赋值
            this.audioClips = audioClips;

            if (audioClips.Length > 1)
                this.random = random;
            else
                this.random = false;
            if (random)
                this.loop = true;
            else
                this.loop = loop;

            this.pitch = pitch;
            audioSource.spatialBlend = space3d;
            Volume = volume;

            //位置信息
            if (target == null)
            {
                audioSource.transform.position = pos;
            }
            else
            {
                if (pos == Vector3.zero)
                {
                    this.pos = Vector3.zero;
                    audioSource.transform.position = target.position;
                }
                else
                {
                    this.pos = new Vector3(pos.x * target.lossyScale.x, pos.y * target.lossyScale.y, pos.z * target.lossyScale.z);
                    audioSource.transform.position = target.TransformPoint(this.pos);
                }
            }
        }
        /// <summary>
        /// 播放多段音频时,设置随机间隔
        /// </summary>
        /// <param name="minInterval">最小间隔</param>
        /// <param name="maxInterval">最大间隔</param>
        internal void SetInterval(float minInterval, float maxInterval)
        {
            MinInterval = minInterval;
            MaxInterval = maxInterval;
        }
        /// <summary>
        /// 重设audioClips
        /// 参数为空时不生效
        /// </summary>
        /// <param name="audioClips"></param>
        internal void SetAudioClips(params AudioClip[] audioClips)
        {
            if (audioClips == null || audioClips.Length == 0 || audioClips[0] == null)
                return;
            this.audioClips = audioClips;
        }
        /// <summary>
        /// 如果后续添加其他模板
        /// (说好的对拓展开放,对修改关闭呢。。。这妥妥的相反)
        /// (有需要可以修改一下,把这些内容放到派生类,只是初值不同)
        /// </summary>
        internal void SetOther()
        {
            //never use 警报
#if UNITY_EDITOR
            if (playing || progress == 0 || maxProgress == 0) { }
#endif
        }
        /// <summary>
        /// 禁用,准备回收
        /// </summary>
        internal void SetDisable()
        {
            audioClips = null;
            target = null;
            pos = Vector3.zero;
            IsReleased = true;
            if (audioSource != null)
            {
                //if (audioSource.transform != instance.transform)
                {
                    audioSource.Stop();
                    audioSource.transform.SetParent(instance.transform);
                    audioSource.transform.localPosition = Vector3.zero;
                    audioSource.gameObject.SetActive(false);
                    return;
                }
                //audioSource.enabled = false;
            }
        }
        internal void OnUpdate(float deltaTime)
        {
            //检查是否可用,不可用标记销毁
            if (!IsValid())
            {
                IsDestroyed = true;
                Release();
                playing = false;
                return;
            }

#if UNITY_EDITOR
            //面板显示进度
            progress = Time.realtimeSinceStartup - StartTime;
            if (random)
            {
                progress = audioSource.time;
            }
            if (random || stopTime > 0)
            {
                if (progress > maxProgress)
                {
                    progress = maxProgress;
                }
            }
            else if (loop)
            {
                progress = audioSource.time;
                if (progress > maxProgress)
                {
                    progress -= maxProgress;
                }
            }

#if !Sirenix_OdinInspector
            progress /= maxProgress;
#endif

#endif
            //跟随目标移动,而不作为目标的子物体,防止随目标一起销毁
            if (target != null)
            {
                if (pos == Vector3.zero)
                {
                    audioSource.transform.position = target.position;
                }
                else
                {
                    audioSource.transform.position = target.TransformPoint(pos);
                }
            }

            //渐出
            if (stoping)
            {
                if (TransitionTime == 0 ||
                    volumescale <= 0)
                {
                    volumescale = 0;
                    audioSource.volume = 0;
                    IsPlayFinished = true;
                    return;
                }
                audioSource.volume = Volume * (IsMusic ? instance.MusicVolume : instance.SoundVolume) * volumescale;
                volumescale -= deltaTime / TransitionTime;
                return;
            }

            //定时停止播放
            if (stopTime > 0 && Time.time > stopTime)
            {
                Stop(TransitionTime, false);
            }

            //音量过渡
            if (TransitionTime == 0 ||
                volumescale >= 1)
            {
                volumescale = 1;
            }
            else
            {
                volumescale += deltaTime / TransitionTime;
            }
            audioSource.volume = Volume * (IsMusic ? instance.MusicVolume : instance.SoundVolume) * volumescale;

            //播放完成不需要切换音频
            if (IsPlayFinished || (IsMusic && loop))
                return;

            //检查播放进度,播放下一个音频,或标记为播放完成
            //暂时没有排除audioClips数组中有空指针的情况
            if (Time.realtimeSinceStartup >= endTime)
            {
                if (random)//随机顺序
                {
                    CurrIdex = Random.Range(0, audioClips.Length);
                    Play();
                    return;
                }
                CurrIdex++;
                if (CurrIdex < audioClips.Length)//顺序
                {
                    Play();
                    return;
                }
                if (loop)//顺序循环
                {
                    CurrIdex = 0;
                    Play();
                    return;
                }
                //顺序不循环==完成播放
                IsPlayFinished = true;
                playing = false;
            }
        }
        /// <summary>
        /// 播放
        /// </summary>
        private void Play()
        {
            if (CurrIdex >= audioClips.Length || audioClips[CurrIdex] == null)
            {
                //audioSource.Stop();
                return;
            }

            playing = true;
            audioSource.gameObject.SetActive(true);
            audioSource.clip = audioClips[CurrIdex];
            if (MinInterval == MaxInterval)
            {
                endTime = Time.realtimeSinceStartup + audioClips[CurrIdex].length + MinInterval;
            }
            else
            {
                endTime = Time.realtimeSinceStartup + audioClips[CurrIdex].length + Random.Range(MinInterval, MaxInterval);
            }
            audioSource.Play();
#if Sirenix_OdinInspector
            //面板显示进度
            if (stopTime <= 0)
            {
                if (random)
                {
                    maxProgress = audioClips[CurrIdex].length;
                }
            }
#elif UNITY_EDITOR
            maxProgress = 1;
#endif
        }
        /// <summary>
        /// 停止播放
        /// </summary>
        /// <param name="transitionTime">渐出时间</param>
        /// <param name="waitFinished">是否等待播放完成,若等待完成则没有渐出效果</param>
        internal void Stop(float transitionTime, bool waitFinished)
        {
            playing = false;
            TransitionTime = transitionTime;
            if (waitFinished)
            {
                CurrIdex = audioClips.Length;
                audioSource.loop = false;
                endTime = Time.realtimeSinceStartup + (audioSource.clip.length - audioSource.time % audioSource.clip.length);
                loop = false;
            }
            else
            {
                stoping = true;
            }
        }
        /// <summary>
        /// 设置剩余长度
        /// </summary>
        /// <param name="l"></param>
        internal void SetRemainingLength(float l, float transitionTime)
        {
            TransitionTime = transitionTime;
            stopTime = Time.time + l;
#if Sirenix_OdinInspector
            maxProgress = Time.realtimeSinceStartup + l - StartTime;
#endif
            loop = true;
        }
        /// <summary>
        /// 检查是否有效
        /// </summary>
        /// <returns></returns>
        private bool IsValid()
        {
            if (IsDestroyed)
                return false;
            if (audioSource == null)
                return false;
            return true;
        }
        /// <summary>
        /// 释放资源,准备销毁
        /// </summary>
        internal void Release()
        {
            playing = false;
            IsDestroyed = true;
            if (audioSource != null /*&&
                audioSource.transform != instance.transform*/)
            {
                Destroy(audioSource.gameObject);
            }
            if (instance.AudioControllerDic.ContainsKey(ID))
                instance.AudioControllerDic.Remove(ID);
            target = null;
            audioClips = null;
        }
        /// <summary>
        /// 是否正在播放
        /// </summary>
        /// <returns></returns>
        internal bool IsPlaying()
        {
            return !IsDestroyed &&
                   !stoping &&
                   !IsPlayFinished &&
                   audioSource.isPlaying;
        }
        /// <summary>
        /// 是否正在播放某段音频
        /// </summary>
        /// <param name="clipName"></param>
        /// <returns></returns>
        internal bool IsPlaying(string clipName)
        {
            return !IsDestroyed &&
                   !stoping &&
                   !IsPlayFinished &&
                   clipName.EndsWith(audioSource.clip.name) &&
                   audioSource.isPlaying;
        }
    }

    #endregion 私有成员
}


 

2017-08-11 16:34:58 lr123838 阅读数 684
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

unity3d的音乐部分:AudioSource、AudioClip、AudioMixer(比较新版才有的)
这里写图片描述
右键新建一个AudioSource,在设置界面关联音乐文件到AudioClip,这样跑起来就能听到声音了。Loop设置是否循环播放,Volume音效从0-1。PlayOnAwake选择是否在场景Awake就开始播放,如果是条件触发的音效就不要勾选啦,这样子需要写个脚本来控制播放。

void Start () {
    audioSource = this.GetComponent<AudioSource> ();
}
public void addVolume(){
        audioSource.volume = audioSource.volume+0.1f;
        Debug.Log (audioSource.volume);
    }

    public void subVolume(){
        audioSource.volume = audioSource.volume-0.1f;
        Debug.Log (audioSource.volume);
    }

    public void play() {
        audioSource.Play ();
    }

    public void pause(){
        audioSource.Pause ();
    }

因为博主需要尽快上手,所以并没有深入,见谅。现在的时代啊,节奏快了!

2014-02-05 20:28:12 SDDCCCC 阅读数 3979
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

声音和视频是3d作品中不可或缺的元素。在unity3d中添加声音和视频元素,并且编写脚本实现声音和视频的控制播放是必要的操作。

1.首先给某个component组件添加Audio Source属性,定义为声音源,并且一般会给主摄像机添加Audio Listener定义为声音的听者。我在做的时候给场景中的一个音响模型添加了Audio Source的属性,并且因为选项为3D sound因此在场景中声音就有了在实际中的远近效果。勾选其中的Play on Awake自动播放之后,运行的时候就可以自动播放声音效果;


2.编写脚本进行声音片段的播放,暂停,以及所播放的声音片段的选择的控制,所写的简单脚本如下:

#pragma strict
//引入声音源
@script RequireComponent(AudioSource)
//定义变量指向另一个声音片段资源
var SecondSong:AudioClip;

function Start () {
	audio.loop = true;
}

function OnGUI() {//设置点击GUI上的各个按钮所对应的事件
	if(GUILayout.Button("Play/Continue"))
	{
		if(!audio.isPlaying)
		{
			audio.Play();
		}
	}
	if(GUILayout.Button("Pause"))
	{
		audio.Pause();
	}
	if(GUILayout.Button("stop"))
	{
		audio.Stop();
	}
	if(GUILayout.Button("Play another song"))
	{
		audio.Stop();
		audio.PlayOneShot(SecondSong);
	}
}

在声音源的选项中定义脚本中变量所对应的声音片段:

运行后的效果,可以用鼠标点击左上角GUI菜单的按钮来控制声音资源的播放,暂停,切换等等:


3.对于视频的操作和声音差不多,不过视频操作的时候需要PRO版本,官网下的只要破解一下就可以了。 将视频资源拖拽到带有render属性的对象上面,我创建了一个plane用来播放视频片段


然后编写脚本控制初始状态,设置为初始即播放,简单的脚本如下:

using UnityEngine;
using System.Collections;

public class AudioPlay : MonoBehaviour {
	public MovieTexture audioplay;

	// Use this for initialization
	void Start () {
		renderer.material.mainTexture = audioplay;
		audioplay.loop = true;
		audioplay.Play ();
	}
	// Update is called once per frame
	void Update () {
	
	}
}
运行一下即可看见效果


至此实现了视频和声音资源的播放以及脚本的控制

没有更多推荐了,返回首页