Cz_mirror Game開発備忘録

週末にUnity でゲーム開発をしています。ゲーム開発を通じて得た情報の備忘録として活用するブログになります。

【Unity】デリゲートを使ったアイテム実装、UniRXによるUI更新

以前で1週間ゲームジャムで開発したTurboSobaではUniRXの他に、デリゲートなども使用しています。継承とデリゲートを利用することでなるべく重複する処理を減らすように工夫してみました。

f:id:godhandevilleg:20180911173005p:plain

TurboSobaのアイテム実装について

TurboSobaではいくつかアイテムを用意していて、それらの処理をする際にアイテムの基底クラスを作り、その中で共通する処理をデリゲートにしています。実際のアイテムで使用する派生クラスにて、それぞれのアイテムの処理をデリゲート化した関数に注入する方法にしてみました。

アイテムの基底クラスについて

アイテムの共通処理部分をまとめるために基底クラスを作成してみました。共通処理はプレイヤーの取得処理と取得後の消滅処理になります。

IPickableItem.cs

アイテムの基底クラス、インターフェースも作っていますが、こちらは今回は未使用になります。(アイテムを横取りするお邪魔キャラなどを作った時に改めて使ってみようかなと思います。)

using System;
using UnityEngine;
using TurboSoba.Scripts.Player;

namespace TurboSoba.Scripts.Item
{
    
    public interface IPickableItem
    {
        void Pickable();
    }

    // アイテム基底クラス
    public abstract class ItemBase : MonoBehaviour
    {
        // アイテム取得処理デリゲート
        protected delegate void PickupDelegate();
        protected PickupDelegate pickupDelegate;

        protected virtual void Start()
        {
            // アイテム消去処理デリゲートに消去処理をセット(各アイテム共通処理)
            pickupDelegate = ItemDestroy;
        }

        // プレイヤー接触時のアイテム取得処理実行用
        protected virtual void OnTriggerEnter(Collider other)
        {
            var playerComponent = other.gameObject.GetComponent<PlayerCore>();

            if (playerComponent != null)
            {
                PickupItem();
            }
        }

        // アイテムを取得した時に、それぞれのアイテムクラスで設定されている処理を実行
        protected void PickupItem()
        {
            if (pickupDelegate != null)
            {
                pickupDelegate();
            }
        }

       // 取得アイテム消去処理
        protected void ItemDestroy()
        {
            Destroy(gameObject);
        }

    }

    // 固定アイテム用クラス
    public abstract class FixedItem : ItemBase
    {
        
    }


}

アイテムの派生クラスについて

クリアに必要な蕎麦の他にお助けアイテムとしてターボとタイマーを用意していたので、それぞれのアイテムごとに派生クラスを用意してみました。

ItemTimer.cs

派生クラス タイマー取得時の処理を記述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniRx;
using TurboSoba.Scripts.Item;
using TurboSoba.Scripts.Timecontroller;

namespace TurboSoba.Scripts.Item
{
    public class ItemTimer : FixedItem
    {
        static GameObject gameCore;

        protected override void Start()
        {
            base.Start();
            gameCore = GameObject.Find("GameCore");
            pickupDelegate += PickupTime;
        }

        void PickupTime()
        {
            gameCore.GetComponent<TimeController>().PickupTime();
        }
    }
}

ItemTurbo.cs

派生クラス ターボ取得時の処理を記述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TurboSoba.Scripts.Item;
using TurboSoba.Scripts.Player;

namespace TurboSoba.Scripts.Item
{
    public class ItemTurbo : FixedItem
    {
        static GameObject player;

        protected override void Start()
        {
            base.Start();
            Setup();
            pickupDelegate += PickupTurbo;
        }

        void Setup()
        {
            player = GameObject.Find("Player");
        }

        void PickupTurbo()
        {
            if (player == null)
            {
                Setup();
            }

            var playerComponent = player.GetComponent<PlayerCore>();
            playerComponent.Turbo();
        }
    }
}

ItemSoba.cs

派生クラス 蕎麦取得時の処理を記述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TurboSoba.Scripts.Item;
using UniRx;
using UniRx.Triggers;

namespace TurboSoba.Scripts.Item
{
    public class ItemSoba : FixedItem
    {
        static public IntReactiveProperty TotalSoba = new IntReactiveProperty(0);
        static public IntReactiveProperty CurrentSoba = new IntReactiveProperty(0);

        protected override void Start()
        {
            base.Start();
            TotalSoba.Value++;
            pickupDelegate += PickupSoba;
        }

        static public void ItemReset()
        {
            TotalSoba.Value = 0;
            CurrentSoba.Value = 0;
        }

        void PickupSoba()
        {
            CurrentSoba.Value++;
        }
    }
}

PresenterSoba.cs

蕎麦の残り数を表示するためのプレゼンター、UniRXを用いることで蕎麦のクラスと連携を行うことでUIを更新。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UniRx;
using TurboSoba.Scripts.Item;

// 残りの蕎麦カウント用プレゼンター
public class PresenterSoba : MonoBehaviour
{
    static GameObject sobaUI;

    void Start ()
    {
        Setup();

        ItemSoba.TotalSoba
                .Subscribe(x =>
                          RefreshSobaUI()
                         );
        
        ItemSoba.CurrentSoba
                .Subscribe(x =>
                           RefreshSobaUI()
                          );
    }

    void Setup()
    {
        sobaUI = GameObject.Find("Canvas/RestSoba");
    }
    
    void RefreshSobaUI()
    {
        var _totalSoba = ItemSoba.TotalSoba;
        var _currentSoba = ItemSoba.CurrentSoba;

        if (!sobaUI)
        {
            Setup();
        }

        sobaUI.GetComponent<Text>().text = "Soba " + _currentSoba.ToString() + "/" + _totalSoba.ToString();
    }
}

デリゲートとUniRXを導入してみて

 今回デリゲートとUniRXを導入してみて、かなりコードの記述が簡略化した印象を受けました。

以前作ったゲームではアイテムのクラスを複製してしまっていたのですが、デリゲートを併用することで、共通する処理をうまくわけて、必要な処理のみ注入することができました。