MawaLog

一日一日、楽しく生きる。技術と音楽が好き。

Unity::UniRx実装例メモ::ObserveEveryValueChanged()のゲームにおけるケース別実装例::「スコアが加点されたら加点状況に応じてUIに反映&効果音再生」など

f:id:k_mawa:20180405143952j:plain

コメント

今回のゲーム開発で使ったUniRxの実装例をメモしておこうと思います。ゲームで定義した値に変化があったら実行ではObserveEveryValueChanged()を使うと直観的にも挙動が分かりやすい実装になった!今回の例は、UniRxで、「敵を倒して加点したら、点数変動を察知して、スコアTextに反映」と、「体力が最初10だけど0になったらゲームオーバーシーンへ移動」の実装例をご紹介します。事例としては応用かけやすいかなと・・・^^

参考資料

大変参考になりました!^^ ありがとうございます!

qiita.com

実際の実装後の動き

下記の実装例コードはこの自分で作ったゲームで実際に動いています^^「敵を倒して加点したら、点数変動を察知して、スコアTextに反映」と、「体力が最初10だけど0になったらゲームオーバーシーンへ移動」がUniRxで実装しています。

コード解説::ReactivePropertyの値の監視が2つ以上のスクリプトにまたがる場合(汎用性高い)

この実装は「敵を倒して加点したら、点数変動を察知して、スコアTextに反映」の部分です。

//ReactiveProperty<T>を設定したスクリプト

using UniRx;
using UniRx.Triggers; //いらないかも
using UnityEngine.UI;


public class GameMasterScript : MonoBehaviour {

    public static ReactiveProperty<int> rp_gameScore = new ReactiveProperty<int>(0);
    //↑要するに、public static int gameScore = 0;
    //の代わりに設定するゲームスコアの値

    //スコア加点時に再生する音声のセッティング
    private AudioSource audioSource_hit;
    public AudioClip sound_hit;

    [SerializeField]
    private Text _text;//スコア表示する変数欄

void Start () {

        //1行目:rp_gameScoreの値に変化があったら、
        //(※ReactiveProperty<int>の値は.Valueで取り出す)
        //2行目:.SubscribeToText(_text)=>_textに値を流す
        rp_gameScore.ObserveEveryValueChanged(_ => _.Value)
            .SubscribeToText(_text);

        //1行目:rp_gameScoreの値に変化があったら、
        //2行目:得点が1点以上の場合のみ.Subscribeに流す(0点も含めるとゲームスタート時に1度音が再生されてしまうのを防ぐ)
        //3行目:スコア加点時の音声ファイル再生
        rp_gameScore.ObserveEveryValueChanged(_ => _.Value)
            .Where(_ => _ > 0)
            .Subscribe(_ => audioSource_hit.Play());

}

//値が変化する関数を記述したスクリプト

using UniRx;

void OnCollisionEnter(Collision other)
    {
        if (other.gameObject.tag == "Ghost")
        {
            //衝突したら、ReactiveProperty<int>の
            //オブジェクトの値を変化させる(加点)
            //(変化があった時点で
            //  すべての監視設定済みSubscribeが発火)
            GameMasterScript.rp_gameScore.Value += 1;

        }
}

コード解説::ReactivePropertyの値の監視が1つのスクリプトで完結する場合(汎用性低め)

この実装は「体力が最初10だけど0になったらゲームオーバーシーンへ移動」の部分です。

//ひとつのスクリプト内で完結するタイプの書き方

using UniRx;
using UniRx.Triggers; //いらんかも
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class ColliisionController : MonoBehaviour
{
    
    ReactiveProperty<int> score = new ReactiveProperty<int>(10);
    //↑要するに、scoreは、HPscoreとしてint変数と同じ使い方で
    //ReactiveExtention<int>を設定する
    //public staticはつけないから他のスクリプトで
    //参照できない(参照させたかったらpublic staticつける)


    // Use this for initialization
    void Start()
    {
        //1行目:scoreの値に変化があったら、
        //(※ReactiveProperty<int>の値は.Valueで取り出す)
        //2行目:scoreが0以下のとき(HPが0になったら)
        //3行目:"Ending"シーンへ移動
        score.ObserveEveryValueChanged(_ => _.Value)
            .Where(_ => _ <= 0)
            .Subscribe(_ => SceneManager.LoadScene("Ending"));
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    void OnCollisionEnter(Collision other)
    {
        if (other.gameObject.tag == "Ghost")
        {
          
            score.Value -= 1;
            //HPscoreをー1する。
            //(これにより、ObserveEveryValueChangedが
            //   反応する)

        }

}

こんな感じですね^^