UNITY中FMOD音效插件使用

在UNITY中使用FMOD插件,直接控制音乐,音效。



FMOD下载

FMOD STUDIO的版本与插件要保持一致。


FMOD STUDIO使用教程



UNITY引入package

FMOD - Edit Setting 3个选项:Project,Single Platform Build,Multiple Platform Build

Project路径指定FMOD工程,其余2个路径指定FMOD导出的bank所在文件夹。

可以指定UNITY工程外路径,如果需要多人同步也可以用Assets\路径 (Mac下用 [/])


指定后插件会自动在Assets/StreamingAssets将bank导入。

注意:导出安卓工程时,FMOD的BANK文件没有被加密放在assets\bin文件夹内,而是直接在assets文件夹下


Live Update选项Enabled时,可以直接在FMOD STUDIO中调试音乐音效。


UNITY内代码部分:

using UnityEngine;
using System;
using System.Collections.Generic;
using FMOD.Studio;
using FMODUnity;


public class SoundManager <T>: MonoBehaviour where T: Component{
	protected static T _instance;

	public static T instance {
		get {
			if (_instance.IsNull())
				_instance = FindObjectOfType<T>();

			return _instance;
		}
	}

	public static bool DoesInstanceExist {
		get {
			return instance != null;
		}
	}


	public BGMPathDefinition[] BGMPathDefinitions;
	protected Dictionary<BGMType, string> BGMPathDict;
	protected BGMType currentAmbientAudio;
	//一个声音实例,可控制。
	//循环播放的可以创建一个,要手动release, OneShot 为true播放完自动release.
	//http://www.fmod.org/docs/content/generated/studio_api_EventInstance.html
	//http://www.fmod.org/docs/content/generated/FMOD_Studio_EventDescription_IsOneshot.html
	protected EventInstance BGMEvent;

	////用来读取声音在工程里面的设置信息,用不到
	////http://www.fmod.org/docs/content/generated/studio_api_EventDescription.html
	//private EventDescription musicDescription;

	protected Dictionary<string, EventInstance> loopingSoundEvents = new Dictionary<string, EventInstance>();

	protected List<EventInstance> pausedSoundEvents;
	protected const int minPathLength = 7;
	protected virtual void Awake() {
		_instance = GetComponent<T>();

		BGMPathDict = new Dictionary<BGMType, string>();
		foreach (var ambientAudioDefinition in BGMPathDefinitions) {
			BGMPathDict.Add(ambientAudioDefinition.ambientAudioType, ambientAudioDefinition.path);
		}
	}

	protected virtual void OnDestroy() {
		StopAndReleaseAll();

		if (BGMEvent != null) {
			BGMEvent.stop(STOP_MODE.IMMEDIATE);
			BGMEvent.release();
		}
		_instance = null;
	}


	public virtual void StopAndReleaseAll() {
		foreach (var sound in loopingSoundEvents.Values) {
			if (sound == null)
				continue;

			sound.stop(STOP_MODE.IMMEDIATE);
			sound.release();
		}

		loopingSoundEvents.Clear();
	}


	public virtual void pauseAll() {
		pausedSoundEvents = new List<EventInstance>();

		foreach (var loopingInstance in loopingSoundEvents.Values) {
			if (loopingInstance == null)
				continue;

			PLAYBACK_STATE state;
			loopingInstance.getPlaybackState(out state);
			if (state == PLAYBACK_STATE.PLAYING
				|| state == PLAYBACK_STATE.STARTING) {
				loopingInstance.setPaused(true);
				pausedSoundEvents.Add(loopingInstance);
			}
		}

		PauseBGM(true);
	}

	public virtual void resumeAll() {
		PauseBGM(!GameController.Instance.MusicEnable);

		if (!GameController.Instance.SFXEnable || pausedSoundEvents == null)
			return;

		foreach (var pausedSound in pausedSoundEvents) {
			pausedSound.setPaused(false);
		}
	}

	#region BGM

	public virtual void PlayBGM(BGMType type) {
		currentAmbientAudio = type;

		if (GameController.Instance.MusicEnable) {
			CheckBGMEventInstance();
		}
	}

	public virtual void PauseBGM(bool pause) {
		if (BGMEvent == null)
			CheckBGMEventInstance();

		if (BGMEvent != null)
			BGMEvent.setPaused(pause);
	}

	protected void CheckBGMEventInstance() {

		if (BGMPathDict.ContainsKey(currentAmbientAudio)) {
			//停止之前的,最好可以通过参数变化背景音乐
			if (BGMEvent != null) {
				BGMEvent.stop(STOP_MODE.IMMEDIATE);
				BGMEvent.release();
			}
			BGMEvent = RuntimeManager.CreateInstance(BGMPathDict[currentAmbientAudio]);
			BGMEvent.start();
		}
	}

	#endregion

	#region SFX

	/// <summary>
	/// 播放一次,不能改变任何参数
	/// </summary>
	public virtual void PlaySoundOnce(string sound) {
		if (!GameController.Instance.SFXEnable || string.IsNullOrEmpty(sound))
			return;

		if (sound.Length < minPathLength) {
			Logger.Warning("Wrong Sound Path:" + sound);
			return;
		}

		RuntimeManager.PlayOneShot(sound);
	}

	///// <summary>
	///// 目标位置播放一次(位置不变)
	///// </summary>
	//public void PlaySoundOnce(string Event, Vector3 position) {
	//	if (GameController.Instance.SFXEnable)
	//		RuntimeManager.PlayOneShot(Event, position);
	//}

	///// <summary>
	///// 播放一次,位置在attach上(跟着attach移动)
	///// </summary>
	//public void PlaySoundOnce(string Event, GameObject attach) {
	//	if (GameController.Instance.SFXEnable)
	//		RuntimeManager.PlayOneShotAttached(Event, attach);
	//}

	/// <summary>
	/// 循环播放,要Fmod工程内OneShot为false
	/// </summary>
	public virtual EventInstance PlayLoopSounds(string sound) {
		if (!GameController.Instance.SFXEnable || string.IsNullOrEmpty(sound))
			return null;

		if (sound.Length < minPathLength) {
			Logger.Warning("Wrong Sound Path:" + sound);
			return null;
		}

		if (HavaEventInstance(sound)) {
			loopingSoundEvents[sound].start();
			return loopingSoundEvents[sound];
		}

		var newInstance = RuntimeManager.CreateInstance(sound);

		newInstance.start();
		loopingSoundEvents[sound] = newInstance;

		return newInstance;
	}

	/// <summary>
	/// 暂停指定循环音效
	/// </summary>
	public bool PauseSound(string sound, bool pause = true) {
		if (HavaEventInstance(sound)) {
			var result = loopingSoundEvents[sound].setPaused(pause && GameController.Instance.SFXEnable);
			return result == FMOD.RESULT.OK;
		}

		return false;
	}
	/// <summary>
	/// 停止指定循环音效,并释放
	/// </summary>
	public bool StopSound(string sound) {
		if (HavaEventInstance(sound)) {
			var result = loopingSoundEvents[sound].stop(STOP_MODE.IMMEDIATE);
			loopingSoundEvents[sound].release();
			loopingSoundEvents.Remove(sound);
			return result == FMOD.RESULT.OK;
		}

		return false;
	}

	protected bool HavaEventInstance(string sound) {
		return !string.IsNullOrEmpty(sound) && loopingSoundEvents.ContainsKey(sound) && !loopingSoundEvents[sound].IsNull();
	}
	#endregion

	//void OnApplicationPause(bool didPause) {
	//	if (didPause) {
	//		pauseAll();
	//	}
	//	else {
	//		resumeAll();
	//	}
	//}

	void OnApplicationFocus(bool focus) {
		if (focus) {
			resumeAll();
		}
		else {
			pauseAll();
		}
	}
}


[Serializable]
public class BGMPathDefinition {
	public BGMType ambientAudioType;

	[EventRef]
	public string path;
}

public enum BGMType {
	Mainmenu = 0,
	IngameRunning = 20,
}


FMOD STUDIO的版本与插件要保持一致。
FMOD STUDIO的版本与插件要保持一致。
阅读更多
想对作者说点什么? 我来说一句

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