ソースコード
どんなサウンドを実装したか、実装するべきなのかを一目でわかるようにします。
作ったわけ
学生で集まってゲームを作るときに毎回サウンドデータを作り忘れていたり、実装し忘れたりがあったので仮実装できる仕組みがあったら便利だと思いました。
(仕様作成とプログラミングが同時進行で進んでるので起こる問題だとは思いますが…)
プランナーが必要そうなサウンドを表にまとめてサウンドクリエイターが作ってエンジニアが実装します。
ゲームが完成してから一度遊んでみると『このサウンドなくね?』みたいなこと結構起きるんですよね。
1人でゲームに登場するすべての音を考えれるわけがないのでエンジニアが『ここサウンド必要そうだな』と思った場所にコードを書くとどんなサウンドが必要かを一覧でまとめれるようにしました。
if (Input.GetMouseButtonDown(0))
{
AudioReserveManager.AudioReserve("Player", "歩く", this.transform);
AudioReserveManager.AudioReserve("Player", "走る", this.transform);
AudioReserveManager.AudioReserve("Player", "攻撃", this.transform);
}
どんなオブジェクトがどんな音を出すのかが表になって生成される。
エンジニアは
仕様書には書かれてないが明らかに必要だと思うサウンドを仮実装
プランナーは
自分が思いつかなかった必要なサウンドを仕様書に追加
と相互にやり取りできます。
データを保存する
特に難しいことはせず、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拡張で見やすくします。
読み込むデータを選択できるようにする
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
を使って一覧から選べれる画面を作ります。
一覧表示する
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に保存されてどんな音を今後作るべきなのかわかるようになります!