様々な箇所に登場するオーディオボリュームのコントロール方法(スクリプト編)

ゲームをプレイするときに再生されるサウンド音量は各々の環境で全く異なります。

そのため、ボリュームの制御を行うのはどのゲームでも必須といっていいものです。

今回はボリュームの制御について見ていきたいと思います。

コンテンツ

要件

3Dゲームでは空間にオーディオが配置される上にプレハブの生成によって動的に変化します。

そのため

  • 動的に生成されるオーディオをすべて管理しなければならない
  • オーディオが破棄されたことを管理しなければならない
  • ボリュームが変化されたときに速やかにオーディオに伝えなければならない

このような要件が必要になります。

実装方法

単純に以下のプロセスを事前出来れば解決できる

このようにボリューム変更を一度「ボリューム管理者」を置いて手続きするとここからボリュームガン変更されたとき「ボリューム変更者」がボリュームを変更することで比較的容易に実現できます。

ということでボリューム管理者とボリューム変更者を実装します。

↓ボリューム管理者

public class VolumeManager : MonoBehaviour
{
	/// <summary>インスタンス</summary>
	private static VolumeManager instance = null;

	/// <summary>ボリュームタイプ</summary>
	public enum VolumeType
	{
		None,
		Se,
		Bgm,
	}

	public static VolumeManager Instance
	{
		get
		{
			if(instance == null)
			{
				var obj = new GameObject();
				obj.name = typeof(VolumeManager).Name;
				instance = obj.AddComponent<VolumeManager>();
				DontDestroyOnLoad(obj);
			}
			return instance;
		}
	}

	// ----------------------------------------------
	// 内部メンバ変数

	// 管理してるボリューム変更者
	private Dictionary<int, VolumeChanger> m_changers = new Dictionary<int, VolumeChanger>();

	// 管理してるボリューム値
	private Dictionary<VolumeType, int> m_volumes = new Dictionary<VolumeType, int>();

	/// <summary>
	/// ボリューム取得
	/// </summary>
	/// <param name="type">ボリュームタイプ</param>
	/// <returns>ボリューム</returns>
	public float GetVolume(VolumeType type)
	{
		if(!m_volumes.ContainsKey(type))
		{
			m_volumes.Add(type, PlayerPrefs.GetInt(type.ToString(), 50));
		}
		return m_volumes[type] / 100.0f;
	}

	/// <summary>
	/// ボリュームセット
	/// </summary>
	/// <param name="type">ボリュームタイプ</param>
	/// <param name="volume">ボリューム</param>
	public void SetVolume(VolumeType type, int volume)
	{
		PlayerPrefs.SetInt(type.ToString(), volume);
		if(!m_volumes.ContainsKey(type))
		{
			m_volumes.Add(type, volume);
		}
		else
		{
			m_volumes[type] = volume;
		}
		foreach(var changer in m_changers.Where((a) => a.Value.VolumeType == type))
		{
			changer.Value.Audio.volume = GetVolume(changer.Value.VolumeType);
		}
	}

	/// <summary>
	/// 変更者を登録
	/// </summary>
	/// <param name="volumeChanger">変更者</param>
	/// <returns>管理ID</returns>
	public int RegistChanger(VolumeChanger volumeChanger)
	{
		int max = 1;
		if(m_changers.Count > 0)
		{
			max = m_changers.Max((a) => a.Key) + 1;
		}
		volumeChanger.Audio.volume = GetVolume(volumeChanger.VolumeType);
		m_changers.Add(max, volumeChanger);
		return max;
	}

	/// <summary>
	/// 登録者削除
	/// </summary>
	/// <param name="id">管理ID</param>
	public void DeleteChanger(int id)
	{
		if(m_changers.ContainsKey(id))
		{
			m_changers.Remove(id);
		}
	}
}

ボリューム管理者はシングルトンで実装しどこからでもアクセスできるようにします。

↓ボリューム変更者

[RequireComponent(typeof(AudioSource))]
public class VolumeChanger : MonoBehaviour
{
	// ----------------------------------------------
	// 設定項目

	// ボリュームタイプ
	[SerializeField]
	private VolumeManager.VolumeType m_volumeType = VolumeManager.VolumeType.None;

	// ----------------------------------------------
	// 内部メンバ変数

	// ID
	private int m_id = 0;

	// オーディオ
	private AudioSource m_audio = null;

	// ----------------------------------------------
	// アクセサ

	public AudioSource Audio
	{
		get
		{
			if(m_audio == null)
			{
				m_audio = GetComponent<AudioSource>();
			}
			return m_audio;
		}
	}

	public VolumeManager.VolumeType VolumeType
	{
		get
		{
			return m_volumeType;
		}
	}

	private void Awake()
	{
		m_id = VolumeManager.Instance.RegistChanger(this);
	}


	private void OnDestroy()
	{
		VolumeManager.Instance.DeleteChanger(m_id);
	}
}

あらかじめアタッチしておけば、プレハブが生成されたとき「Awake」から自動的に「ボリューム管理者」に登録イベントが発生し、廃棄時に自動的に登録が破棄されます。

また、

[RequireComponent(typeof(AudioSource))]

こうすることで、このスクリプトはAudioSourceが必須になりたいていの場合は必ず存在することになります。

まとめ

概要の通り

ゲームをプレイするときに再生されるサウンド音量は各々の環境で全く異なります。

そのため、ボリュームの制御を行うのはどのゲームでも必須といっていいものです。

配信を行う場合は、必ずボリュームの設定画面を実装しておき、操作できるようにしておきましょう。

次は実際に使用していきたいと思います。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

ABOUT US
vuniformity誰でもない人
トレンドの行く末を見守っている
仮名を名乗るエンジニア

ゲーム開発は仕事であり趣味である
プログラムだけでなく多種多様なスキルを数多く持つ

ゲーム開発は
ソーシャルゲームを開発運用の経験アリ
ゲーム以外にも経験アリ
Webサービス保守開発等に携わる

ゲームプレイの主な戦場は
FGO
FEH
MTGA
マビノギ
ここでは主にunityroomで公開しているゲーム作り直しの軌跡を綴っていきます