Unity2017.3.0f3でActionとMusicEngineの話


MusicEngineの話もありますが・・・
何に使ったかというと

GGJ2018参加してきました

CRI渋谷会場で、Interstellar Radio Starを作りました。

動画:
https://www.youtube.com/watch?time_continue=3&v=VU3AS9ewDao

Webサイト:
https://globalgamejam.org/2018/games/interstellar-radio-star

今回はすごくスムーズでした

なんとgithubで共有してたけど 一度もトラブルがなかった。

だいたい同じソースを同時に編集したりとか、マージできなかったりとかよくあるのですが。
今回初めて使ったのですが、C#のActionの機能がすごかった。

Actionってなに?

詳しくは c# event Action などで検索してもらったら良いかと。

これ、サウンドの組み込みではとてもありがたくて、
Actionが 例えば、 onEndGame (ゲーム終了時のイベント(コールバック))
といった感じなので、

GameController.cs
    Action onStartGame = () => {};
    Action onSelectStage = () => {};
    Action onEndGame = () => {};
    Action onRestartGame = () => {};

こんな感じで、ゲームで起こりそうなものがアクションイベントになってて

GameController.cs
onEndGame += () => {
 SoundManager.instance.Play("ClearSound");
};

 みたいに、他のソースコードを汚さずにとてもシンプルにサウンド機能の追加が書けるのです。

これ、多人数でやっているとき、ゲームのロジックと、サウンド処理が混在してカオスになるコードが、
とてもすっきりかけて、しかもマージもしやすい。

(裏で、どれだけスレッドとか処理が走るのかとか処理順番はとかはよくわからないですが、少なくともゲームジャムでは便利)

Actionが定義されていれば、サウンドの組み込み担当は、ゲームのソースコードをほぼ理解せずとも、この +=で付け足すだけで良いし、
サウンドのためのコードとかでソースが縦に長くなったりするのがないので、とってもありがたいことだと思われます。

実際のコード 

StageSelectView.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;

public class StageSelectView : MonoBehaviour {
    public Image[] item;
    public Image cursor;
    public int selectedItemIndex = 0;

    public Action<int> onSelectItem = _ => {};
    public Action<int> onDecideItem = _ => {};

    void Start()
    {
        onDecideItem += _ => {
            switch(_)
            {
            case 0:
                SoundManager.Instance.PlayBGM (SoundManager.enum_bgm.gymnopediIntro);
                break;
            case 1:
                SoundManager.Instance.PlayBGM (SoundManager.enum_bgm.bachIntro);
                break;
            case 2:
                SoundManager.Instance.PlayBGM (SoundManager.enum_bgm.kiraIntro);
                break;
            default:
                SoundManager.Instance.PlayBGM (SoundManager.enum_bgm.kiraIntro);
                break;
            }
        };

        SoundManager.Instance.PlaySE (SoundManager.enum_se.noteSound);

    }

    /// <summary>
    /// 項目選択
    /// </summary>
    /// <param name="index">Index.</param>
    public void OnSelectItem(int index) {
        if (selectedItemIndex == index) {
            onDecideItem (index);
            SoundManager.Instance.PlaySE (SoundManager.enum_se.BD);
        } else {
            onSelectItem (index);
            selectedItemIndex = index;
            SoundManager.Instance.PlaySE (SoundManager.enum_se.puls);
        }
    }

    void Update() {
        // cursor移動
        cursor.transform.position = Vector3.Lerp(cursor.transform.position, item[selectedItemIndex].transform.position, 0.8f);

        if (Input.GetKeyDown (KeyCode.LeftArrow) && selectedItemIndex != 0) {
            OnSelectItem (Mathf.Clamp (selectedItemIndex - 1, 0, 2));
        }
        if (Input.GetKeyDown (KeyCode.RightArrow) && selectedItemIndex != 2) {
            OnSelectItem (Mathf.Clamp (selectedItemIndex + 1, 0, 2));
        }
        if (Input.GetKeyDown (KeyCode.Space)) {
            onDecideItem (selectedItemIndex);
        }

    }
}

publicだとどこからでも呼ばれてしまうので

aaa.cs
    public event Action onStartGame = () => {};
    public event Action onSelectStage = () => {};
    public event Action onEndGame = () => {};
    public event Action onRestartGame = () => {};

たとえば、こんな感じにすると、クラス内でこのActionを呼ぶと
外から関連する処理を拡張したりできるようになるのかな・・・

ADX2LEを使う

修正点

小文字にする

このエラー

musicSource_.player

ADX2LEの最新版ではplayerでアクセスできる!

よし。

ちょっとはまったところ

MusicEngineのPlay関数の引数の名前って、ゲームオブジェクトの名前なのですね。
最初キュー名指定していて、うまくいかなくて、なんでだろう・・・ってなってた。

おまけ

OSCのやりとりで、ちゃんとポートに飛んでいるか

sudo tcpdump -i lo0 port 12001

といった感じで、自身の12001にメッセージがきているか調べられる。