Unityでインタラクティブミュージックを実装 with ADX 実装編


# はじめに

Unityと、サウンドミドルウェア「CRI ADX」を連携させ、ゲームの状況によって変化するBGM＝インタラクティブミュージックをセットアップします。

**本記事は以下の記事のUnity版です。**

https://qiita.com/SigRem/items/b53dc03d01c5f8fe1465

記事中では「ADX2 for UE4でインタラクティブミュージック（AtomCraft編)」で用意したサウンドデータ（ビルド後のファイル）を使用します。
記事はUE4向けですが、操作するツールは共通です。
ただし1点、「Atomキューシートバイナリのビルド」画面で、一番左下のオプション「UnityAssets出力」にチェックを入れるのを忘れないようにして下さい。

https://qiita.com/SigRem/items/8af9b7d8445477906741

CRI ADX導入方法や基本的な操作については以下の記事を参照して下さい。

https://qiita.com/Takaaki_Ichijo/items/16e6501fc07f5b3b3377

## やること

- Unityにインポート
- Animation、Animatorでパラメータを操作
- BGMのトラックごとにフェードイン・フェードアウトができるようにする
- テストプレイ

# Unityでのセットアップ

ADXプラグインを導入したUnityプロジェクトを開き、音を出せる状態にします。導入方法については、以下を参照してください。

https://qiita.com/Takaaki_Ichijo/items/16e6501fc07f5b3b3377

## 通常再生の準備

ビルドしたキューシートをインポートし、AtomBrowserに表示されていることを確認します。「Create GameObject」で「IMLoop(CriAtomSource)」をシーン上に配置、「PlayOnStart」にチェックを入れておきます。

![自動再生の設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2576800/c2591237-c3f7-9d03-8516-5215dd9fbb12.png)

設定が終わったら実行し、自動的に再生されることを確認します。

# AISAC値の操作

スタート地点ではBGMは鳴らず、プレイヤーのいる位置によってAパート、Bパート、Cパートと次々にフェードインする、といったインタラクティブミュージックを実装します。

## テスト用フィールドの作成

今回はBGMの変化が効果的にテストできるよう、こんなフィールドを用意します。壁はコライダーをイメージしやすくするためのものなので、なくても問題ありません。

![テスト用フィールド](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2576800/6d6c5614-959d-a1bd-4e51-305de57fc2d1.png)

カプセル型のオブジェクトはプレイヤー代わりです。「GameObject」＞「3DObject」＞「Capsule」で作成、「Rigidbody」コンポーネントをアタッチしてis Kinematicとis Triggerにチェックを入れます。「Player」というTagを新規作成し設定します。（大文字小文字に注意）

![タグの設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2576800/dfed3eb7-3c30-983c-f447-6e7e3dfd9004.png)

A、B、Cの各パートエリアに入ったことを感知するため、BoxColliderを配置します。親となるGameObjectの名前は「Trigger_Apart」「Trigger_Bpart」「Trigger_Cpart」としておきましょう。AがB、BがCを内包するよう、各パートエリアの座標と大きさを調整します。

![コライダーの設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2576800/d452b8e5-6dd5-098d-75af-7ace42edac32.png)

さらに「Animator」コンポーネントと以下の「ADXController.cs」をアタッチします。「ADXController.cs」の「bgmCriAtomSource」には「IMLoop(CriAtomSource)」を設定、「Trigger_Apart」「Trigger_Bpart」「Trigger_Cpart」の「controlName」はそれぞれ「AisacControl_00」「AisacControl_01」「AisacControl_02」とします（AtomCraftで設定したAISACコントロールの名前を入れます）

![サンプルスクリプトの設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2576800/55a8d213-3335-d005-0d7e-a2a8e08e7460.png)

「ADXController.cs」の処理としては、「aisicValue」を常に監視しておりその値を「IMLoop(CriAtomSource)」のAISACコントロールに渡すというものです。（初期値は0に設定）
また「OnTrigger〇〇」では自身の「BoxCollider」にプレイヤーが侵入した場合にAnimatorにそのことを知らせます。

```AdxControll.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AdxControll : MonoBehaviour
{
		public CriAtomSource bgmCriAtomSource;
    private Animator animator;
    public string controlName;
    public float aisicValue;

    void Start()
    {
        bgmCriAtomSource.SetAisacControl(controlName, 0);
        animator = GetComponent<Animator>();
    }

    void Update()
    {
        bgmCriAtomSource.SetAisacControl(controlName, aisicValue);
    }

    public void SetValueToBGMAISAC(float aisacValue)
    {
        bgmCriAtomSource.SetAisacControl("BgmMixControl", aisacValue);
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.tag == "Player") animator.SetTrigger("FadeIn");
    }

    private void OnTriggerExit(Collider other)
    {
        if (other.gameObject.tag == "Player") animator.SetTrigger("FadeOut");
    }
}
```

## AISAC値の制御

今回の例ではUnity標準のAnimation、Animatorの機能を利用し、以下のオブジェクトの作成と設定をします。

![作成するオブジェクト](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2576800/2dbaee78-2a0d-4955-dcc5-80851a4647cc.png)
![ループしないように設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2576800/84dc99b1-4ddb-7c54-578a-eb3df6759ee9.png)
![Animatorの設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2576800/6498b032-8cca-01dd-549f-9189dd6441c4.png)

- 「IMLoop」という名前の「Animator Controller」を作成
- 「FadeIn」「FadeOut」という名前の「Animation」を作成しLoopTimeのチェックを外す
- 前項で作成した全ての「Trigger_○part」オブジェクトの「Animator」の「Controller」に「IMLoop」を設定

## Animatorの設定

IMLoopをダブルクリックし以下の画像のように設定します。
Animatorでは外部の入力値によってどのようなAnimationを実行するかを設定します。Box Colliderにプレイヤーが侵入（退出）した場合に「FadeIn」「FadeOut」という入力を受け取り、Animationで設定するフェード処理が実行されるようにします。

![Animatorの設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2576800/e0fa3d06-3408-e171-d4d8-dfd2c643a519.png)

![Conditionsの設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2576800/0a990f2a-e984-08e6-8c51-8fcd6f7ea255.png)

- ＋をクリックし「FadeOut」「FadeIn」という名前のTriggerを作成
- ステートを追加し「Initial」「FadeOutState」「FadeInState」という名前に設定
- 「FadeOutState」「FadeInState」の「Motion」をそれぞれ「FadeOut」「FadeIn」に設定
- MakeTransitionで各ステートを繋ぎ「Condition」を設定する
    - 「FadeInState」へ向かうTransitionでは「FadeIn」を設定
    - 「FadeOutState」へ向かうTransitionでは「FadeOut」を設定

## Animationの設定

「FadeIn」「FadeOut」をダブルクリックし以下の画像のように設定します。
AnimationはAnimatorから呼び出して使用します。呼び出された場合、設定するアニメーションカーブに従って「ADXController.cs」の「aisicValue」を変化させます。「ADXController.cs」が「aisicValue」を「AISACコントロール」に適用することにより、各トラックがフェードすることになります。

![アニメーションカーブの設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2576800/3f57c624-a4b7-592c-ba60-9c1abe1c9d16.png)

- 「Trigger_○part」を選択した状態でAnimationタブを開く
- 「AddProperty」＞「AdxControll」＞「AisacValue」を追加
- 「Curves」タブでAISACに値与えるためのカーブを設定
    - 「FadeIn」では0:00は0、1:00は1に設定
    - 「FadeOut」では0:00は1、1:00は0に設定

## テスト実行

ここまで出来たら実行し、プレイヤーをSceneビューで動かして「Trigger_○part」それぞれのコライダーの中に移動させてみます。

想定通り、Aパート、Bパート、Cパートと次々にフェードイン（アウト）するかどうか確認します。

# その他

## AdxControll.csについて

サンプルでは標準の機能で簡単に実装するため、UpdateでAisacValueを監視してSetAisacControlを実行、その値はAnimationで変更という方法をとっています。この場合、AisacValueに変化がない場合もUpdate処理が走り無駄な負荷が増えるため、Updateは使わず、Tweenライブラリで変化させたりUniRxのReactivePropertyを利用したりするほうが良いかもしれません。