はじめに
「アニメーション」と「効果音/声」を同期させたい場面って多々ありますよね。
方法自体は色々あると思うのですが、今回制作しているゲームの場合、
アニメーションや音声の数が膨大なのが問題でした。
※ちなみにアニメーションはAnimatorを使って制御しています。
同期方法の検討
まず同期方法ですが、一番初めに検討したのは「Animation Event」です。
この方法なら確実に同期が取れる訳なのですが、
アニメーションが多いと対応しきれません!
そもそもアニメーションを更新したり差し替えたりする可能性も高かったため、
今回のゲームに限って言えば、あまり現実的な方法とは言えませんでした。
音声とアニメーションの同期をもっとシンプルに考え、
事前にアニメーションと音声を、タイミングを合わせた状態でそれぞれ作成しておき、
「同時に再生」するだけで十分だろう、という方向で検討する事にしました。
同時再生方法の検討
今回実装しているアニメーションをカテゴライズすると、以下の種類に分かれます。
A. トリガー駆動用モーション
B. アイドリング用モーション
C. ブレンド用モーション
「A. トリガー駆動用モーション」については、
アニメーションのトリガーを有効にするタイミングで、
同時に音声の再生を開始すれば良い為、特別な実装は必要ありません。
※今回の場合は、シナリオ側で同時に呼び出せば良いだけです。
問題は「B. アイドリング用モーション」と「C. ブレンド用モーション」です。
この2つは常時ループで再生している為、どこかに
アニメーション開始を検知して音声を再生するという実装が必要でした。
そこで目を付けたのが「StateMachineBehaviour」です。
StateMachineBehaviourの検討
StateMachineBehaviourはAnimatorのステート変更を検知し、
CallBackとして処理を走らせることが出来るクラスです。
しかもサブステートマシンやブレンドツリーでも使用できるため、
今回の方法には打って付けです!
今回使うのは以下です。
・OnStateEnter:ステートに入ったとき実行(AnimationClip/ブレンドツリー用)
・OnStateExit:ステートから出たときに実行(AnimationClip/ブレンドツリー用)
・OnStateMachineEnter:レイヤーに入ったとき実行(サブステートマシン用)
・OnStateMachineExit:レイヤーに入ったとき実行(サブステートマシン用)
StateMachineBehaviourの実装
現状の実装はかなりシンプルで、
Enter時に音声の再生、Exit時に音声の停止をしているだけです。
(下記の内容は、かなり省略して書いてます)
override public void OnStateMachineEnter(Animator animator, int stateMachinePathHash)
{
SoundManager.PlayVoice("ボイス");
SoundManager.PlaySE("効果音");
}
override public void OnStateMachineExit(Animator animator, int stateMachinePathHash)
{
SoundManager.StopVoice("ボイス");
}
ただ上記の実装は、少し見直そうか悩んでいます。
上記の実装でも音声の同時再生は出来ているのですが、
本作ではキャラクターが切り替わる=Animatorが切り替わるので、
その際に問題が生じる可能性があります(=OnStateMachineExitに到達しない可能性)
今回は音声の事しか書いていませんが、
実際はBehaviourを使って他にも色々処理をしており、若干不都合があります。
なのでBehaviourから直接処理を制御するのではなく、
Behaviourは監視専用、もしくはフラグ更新だけにして、
別の常駐するクラスで処理を制御する方が都合が良いかもしれません。
おわりに
タイトルで同期と言いながら、よく考えると単純な同時再生でしたね(すみません)
完全に同期させるのは…正直、手間が掛りすぎます。
でもアニメーションと音を合わせるだけなら、
同時再生でも何とかなるし、実装も簡単なのです。
(アニメーションに合わせた音を作るのは若干面倒ですけどね。。)
ここまで読んで頂き、本当に有難うございました。