LoginSignup
5
3

【Unity】効果音の仮実装システムを作った

Posted at

ソースコード

どんなサウンドを実装したか、実装するべきなのかを一目でわかるようにします。
image.png

作ったわけ

学生で集まってゲームを作るときに毎回サウンドデータを作り忘れていたり、実装し忘れたりがあったので仮実装できる仕組みがあったら便利だと思いました。
(仕様作成とプログラミングが同時進行で進んでるので起こる問題だとは思いますが…)

image.png
プランナーが必要そうなサウンドを表にまとめてサウンドクリエイターが作ってエンジニアが実装します。
image.png
ゲームが完成してから一度遊んでみると『このサウンドなくね?』みたいなこと結構起きるんですよね。
image.png
1人でゲームに登場するすべての音を考えれるわけがないのでエンジニアが『ここサウンド必要そうだな』と思った場所にコードを書くとどんなサウンドが必要かを一覧でまとめれるようにしました。

if (Input.GetMouseButtonDown(0))
{
    AudioReserveManager.AudioReserve("Player", "歩く", this.transform);
    AudioReserveManager.AudioReserve("Player", "走る", this.transform);
    AudioReserveManager.AudioReserve("Player", "攻撃", this.transform);
}

image.png
どんなオブジェクトがどんな音を出すのかが表になって生成される。
image.png
エンジニアは
仕様書には書かれてないが明らかに必要だと思うサウンドを仮実装
プランナーは
自分が思いつかなかった必要なサウンドを仕様書に追加
と相互にやり取りできます。

データを保存する

特に難しいことはせず、Dictionary<string, string>Addするだけです。

// AudioReserveContainer.cs

private Dictionary<string, string> audioReserveDic = new Dictionary<string, string>();

public void RegisterAudioReserve(string speaker, string containText)
{
    if (!audioReserveDic.ContainsKey(containText))
    {
        audioReserveDic.Add(containText, speaker);
    }
}

このDictionaryをUntiyのOnApplicationQuitのタイミングでJsonにします。
OnApplicationQuitはエディターなら再生モード終了時に出るのでこれを使います。

// AudioReserveManager.cs

private void OnApplicationQuit()
{
#if UNITY_EDITOR
    reserveContainer?.SaveLog();
#endif
}

Jsonにする方法は特に難しいことはしてません。工夫した点としてはJsonの名前を現在開いてるシーン名を接頭辞としてくっつけたことです。

string jsonStr = JsonUtility.ToJson(logData, true);
string sceneName = SceneManager.GetActiveScene().name;
string jsonName = AudioReserveStaticData.LOG_JSON_NAME;
string dataPath = Application.dataPath + AudioSettingStaticData.JSON_DIRECTORY_PATH + "/AudioLogData/" + sceneName + "_" + jsonName;

同じ名前のシーンごとにデータが作られて変に上書きされたりすることがありません。

Editor拡張する

プランナーが確認しやすいようにEditor拡張で見やすくします。

読み込むデータを選択できるようにする

image.png

private void OnEnable()
{
    searchPath = Application.dataPath + AudioSettingStaticData.JSON_DIRECTORY_PATH + "/AudioLogData";
    DirectoryInfo dir = new DirectoryInfo(searchPath);
    FileInfo[] info = dir.GetFiles("*.json");

    if (info.Length == 0)
    {
        return;
    }

    jsonDataNames = new string[info.Length];
    for (int i = 0; i < info.Length; i++)
    {
        jsonDataNames[i] = info[i].Name;
    }
}

保存場所に保存されてるJsonを全部探して

using (new GUILayout.VerticalScope())
{
    GUILayout.Label("読み込むデータを選択する");
    using (new GUILayout.HorizontalScope())
    {
        selectedJsonDataIndex.Value = EditorGUILayout.Popup(selectedJsonDataIndex.Value, jsonDataNames);

        if (GUILayout.Button(reloadIconTex, GUILayout.Width(24f)))
        {
            AudioReserveDicFromJson(selectedJsonDataIndex.Value);
        }
    }
}

EditorGUILayout.Popupを使って一覧から選べれる画面を作ります。

一覧表示する

image.png
まず頑張ってJsonをDictionaryに変換します。

private void AudioReserveDicFromJson(int index)
{
    string jsonName = jsonDataNames[index];
    string jsonPath = searchPath + "/" + jsonName;
    string dataStr = string.Empty;

    StreamReader streamReader = new StreamReader(jsonPath);
    dataStr = streamReader.ReadToEnd();
    streamReader.Close();

    AudioReserveLogData audioLogData = JsonUtility.FromJson<AudioReserveLogData>(dataStr);
    audioReserveDic = audioLogData.containTextArray.Select((k, i) => new { k, v = audioLogData.speakerArray[i] }).ToDictionary(a => a.k, a => a.v);

    audioReserveDic = audioReserveDic.OrderBy((x) => x.Value).ToDictionary(a => a.Key, a => a.Value);
}

index読み込むデータを選択できるようにするで選択したデータの番号です。
Dictionaryに変換できたらあとは簡単です。foreachで並べて表示するだけです。

scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);

using (new GUILayout.HorizontalScope())
{
    using (new GUILayout.VerticalScope())
    {
        foreach (var audioReserve in audioReserveDic)
        {
            using (new GUILayout.HorizontalScope("box"))
            {
                string speakerName = audioReserve.Value;
                GUILayout.Label(speakerName);
                if (GUILayout.Button(copyIconTex, GUILayout.Width(24f)))
                {
                    EditorGUIUtility.systemCopyBuffer = speakerName;
                }
            }
        }
    }

    using (new GUILayout.VerticalScope())
    {
        foreach (var audioReserve in audioReserveDic)
        {
            using (new GUILayout.HorizontalScope("box"))
            {
                string containText = audioReserve.Key;
                GUILayout.Label(containText);
                if (GUILayout.Button(copyIconTex, GUILayout.Width(24f)))
                {
                    EditorGUIUtility.systemCopyBuffer = containText;
                }
            }
        }
    }
}

EditorGUILayout.EndScrollView();

完成

これでプログラマは『ここサウンドいるんじゃね?』って思う場所に

AudioReserveManager.AudioReserve("Player", "歩く", this.transform);

を書くだけで勝手にJsonに保存されてどんな音を今後作るべきなのかわかるようになります!

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3