👮

【Unity】独自AudioSourceとAudioTimePoliceで音楽再生管理

2023/11/10に公開

はじめに

こんにちは、まつさこ です。

この記事では、Unityアプリにおいて独自のAudioSourceクラスを用意し、ゲーム全体の音楽再生を管理しやすくする方法を紹介します。

特に、ゲームポーズ時の一括一時停止/再生や、ゲームスピードが変わった時の一括ピッチ変更などを、サウンド系ミドルウェアを使うことなくUnity標準機能のみで実現したい方におススメしたい方法です。

開発環境

筆者の開発環境は以下です。

  • Unity 2021.3.5f1
  • Rider 2023.2.3

音楽再生を統括管理する AudioTimePolice

ゲーム全体の音楽再生を管理する「時間警察」、 AudioTimePolice クラスを作成します。
Staticクラスとして作成します。

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

public static class AudioTimePolice
{
    //AudioSourceオブジェクトを識別するための <InstanceID, Object> Dictionary
    static Dictionary<int, AudioParam> _audioSources = new Dictionary<int, AudioParam>();
    static float _pitch = 1;

    //独自AudioSourceから呼ばれる
    public static void SetDictionary(AudioParam param)
    {
        var instanceId = param.Audio.gameObject.GetInstanceID();
        if (!_audioSources.ContainsKey(instanceId))
        {
            _audioSources.Add(instanceId, param);
            
            //現在のピッチに設定
            if (!param.UnchangeablePitch)
            {
                param.MyAudio._basePitch = _pitch;
                param.Audio.pitch = _pitch;
            }
        }
        else
        {
            Debug.Log(param.Audio.gameObject.name + " is already in dictionary.");
        }
    }
        
    //AudioSourceをDictionaryから削除
    public static void DeleteFromDictionary(AudioSource audio)
    {
        if (audio == null)
        {
            return;
        }
        var instanceId = audio.gameObject.GetInstanceID();
        if (_audioSources.ContainsKey(instanceId))
        {
            _audioSources.Remove(instanceId);
        }
    }
        
    //Pause
    public static void Pause()
    {
        foreach (var audio in _audioSources)
        {
            audio.Value.Audio.Pause();
        }
    }
        
    //UnPause
    public static void UnPause()
    {
        foreach (var audio in _audioSources)
        {
            audio.Value.Audio.UnPause();
        }
    }
        
    //再生スピードを変更
    public static void SetSpeed(float pitch)
    {
        _pitch = pitch;
        foreach (var audio in _audioSources)
        {
            if (!audio.Value.UnchangeablePitch)
            {
                audio.Value.MyAudio._basePitch = _pitch;
                audio.Value.Audio.pitch = _pitch;
            }
        }
    }
        
    //初期化
    public static void Initialize()
    {
        _audioSources = new Dictionary<int, AudioParam>();
        _pitch = 1;
    }

    [Serializable]
    public class AudioParam
    {
        public AudioSource Audio;
        public MyAudioSource MyAudio; //後述する独自AudioSourceクラス
        public bool UnchangeablePitch; //再生スピードを変更するときにピッチを変えないオプション
    }
}

この AudioTimePolice では、次の項で記載する独自AudioSource MyAudioSource クラスをもったオブジェクトを保持し、一括でポーズ/ポーズ解除/スピード変更などを行います。
MyAudioSource をもつオブジェクトが何らかの理由で削除されたときには、正しくDictionaryから削除し、問題が生じないようにしています。

独自AudioSource MyAudioSource

次のようにスクリプトを作成します。

using System;
using UnityEngine;

[RequireComponent(typeof(AudioSource))]
public class MyAudioSource : MonoBehaviour
{
    [SerializeField] bool _unchangeablePitch = false;
    [NonSerialized] public float _basePitch;
    [NonSerialized] public AudioSource _audio;

    void Start()
    {
        _audio = GetComponent<AudioSource>();
        AudioTimePolice.AudioParam param = new AudioTimePolice.AudioParam()
        {
            Audio = _audio,
            MyAudio = this,
            UnchangeablePitch = _unchangeablePitch
        };
        AudioTimePolice.SetDictionary(param);
    }

    //オブジェクトが削除されたときAudioTimePoliceのDictionaryからも削除
    void OnDestroy()
    {
        AudioTimePolice.DeleteFromDictionary(_audio);
    }
}

AudioSource コンポーネントとセットでオブジェクトにつけます。MyAudioSource[RequireComponent(typeof(AudioSource))] が定義されているので、MyAudioSource をオブジェクトにアタッチすると自動的に AudioSource もアタッチされます。

使い方

次の表のように、状況に合わせて関数を呼ぶことで、MyAudioSource を付けたオーディオオブジェクトすべてを一括操作することが出来ます。

状況 呼ぶ関数 備考
ゲームをポーズしたとき AudioTimePolice.Pause()
ポーズを解除したとき AudioTimePolice.UnPause()
ゲームスピードを変更したとき AudioTimePolice.SetSpeed(pitch) 引数 pitch には変化倍率(int)を入れる

まとめ

この記事では、Unityアプリにおいて独自のAudioSourceクラスを作成し、ゲーム全体の音楽再生を管理しやすくする方法を紹介しました。
ミドルウェアは高くてなかなか手が出ないけれど、音楽再生の管理を楽にしたいときなどに、参考にしてみてください。

読んでくださりありがとうございました🤗

Discussion