Unityに関連する記事です

一定の時間が経過するとイベント準備が整うケース


 UniTaskとUniRxを使用して Final FantasyのATBゲージのような、一定時間が経過するとイベントの準備が整うシステムを実装する例です。
ここではボタンが押せるようにしています。

 3回にわけて異なる学習を行いますが、すべて同じ処理として機能します。
徐々に難しくなっていきますので、1回の学習ですべてを覚えようとする必要はありません。

 まずはこの手順の内容を理解してから先に進むようにし、そちらが難しい場合にはまたこちらに戻ってきて復習してみてください。


<実装動画>
動画ファイルへのリンク


設計と概要


 Unityにおいて、UIの表示・操作とゲームシステムの制御という2つの機能は切り離せないことが多いです。
例えば、ゲームの進行に合わせてUIの表示・操作を制御するような機能を実現するには、UIの操作に関する処理とゲームシステムの進行に関する処理をうまく組み合わせる必要があります。

 今回はイベント処理の学習を踏まえて、まずは1つのクラスで処理を実装します。

 クラスについても、非同期処理をコルーチンメソッドで実装するパターンと、UniRx とオブザーバーパターンを利用して実装するパターンの2つを作成します。
UniRx とオブザーバーパターンについては、さらに次の手順で MVP パターンとしての作成方法も学習します。
 

必要な機能

 
 今回実装したい処理においては、以下のような機能を持つクラスが必要です。

 1.ATB値の初期化
 2.攻撃ボタンのクリックによるATB値のリセット
 3.ATBゲージの表示の UI 更新
 4.ATB値の回復
 5.攻撃ボタンの状態の更新

 どのような処理のロジックを構築すれば、これらの機能を実現できるか考えてみてください。
 
 いずれの処理も密接にかかわっています
また例えば、4の処理を作るためには少なくとも「現在値、回復量、上限値といった値を管理する」仕組みを作成する必要があり、
「現在値は上限値を超えないように制御する」といった処理の内部が見えてきます。



 なお処理のデバッグにあたり、UI については最低限のものでよいので自作しておきましょう。

 Image と Button が配置されていれば大丈夫です。


コルーチンを利用した実装例


 先ほどの機能について、1つのクラスにまとめて記述してみます。

 作成するクラスは ATBControllerCoroutine です。
非同期処理にコルーチンメソッドを利用してイベント処理を作成しています。

 まずはこちらで処理の構成を理解するようにしましょう。


ATBControllerCoroutine.cs

<= クリックすると開きます。




 各機能について番号を振っておきました。
どの処理がどこに実装されていて、どういったロジックになっているのかを読み解いてみてください。

 また AttackThreshold、recoveryRateなどのパラメータを調整することで、ATBの動作を調整できます。

 実際にゲームを実行して動作の検証を行いましょう。


UniRx とオブザーバーパターンを利用した実装例


 続いては、先ほどの処理を UniRx とオブザーバーパターンを利用して実装した例を提示します。

 前回作成したクラスを修正するのではなく、新しく ATBController クラスを作成し、比較できるようにしています。
今回も機能ごとの番号を振ってありますので、処理を読み解いてみてください。


ATBController.cs

<= クリックすると開きます。




 コルーチンでの実装時に Start メソッドに記述していた
ボタンのクリック処理と WaitTimer メソッドの処理(ATBの回復処理)をボタンのクリック処理を UniRxのObservableを使って実装しています。

 また、攻撃ボタンの状態を更新するためには UniRxのReactivePropertyを使っていますので、ResetATBメソッドも、単純にATBの値をリセットするだけの実装になっています。

 全体的に、UniRxを使ったシンプルでわかりやすいコードになっていることが分かります。

 こちらも実際にゲームを実行して動作の検証を行いましょう。


ATBControllerの Update 内の処理のリファクタリング


 先ほどの ATBControllerの Update 内の処理を UniRx の Observable にして簡潔に実装することができます。
その結果、Start メソッド内において、ATB値の初期化、リセット、ゲージの表示更新、回復、攻撃ボタンの状態更新などの機能をすべて実装しています。

 以下がその例です。


ATBController.cs

<= クリックすると開きます。



UniRx 全体の解説


 Start メソッドでReactiveProperty<float>型のcurrentATBを0で初期化しています。
ただしこれは宣言の時点で初期化しても問題ありません。

 攻撃ボタンがクリックされたら ResetATB を実行し、currentATB.Valueを0にリセットするストリームを作成しています。
また、ATB値を回復するストリームも作成しています。



 いままで Update メソッド内にあった ATBゲージの表示を更新する処理や、攻撃ボタンの状態を更新する処理を UniRx を利用してストリームを作成しています。
Select オペレータを活用し、currentATBの値がattackThreshold以上であれば攻撃ボタンを有効にし、そうでなければ無効にします。
その際には Subscribe ではなく、SubscribeToInteractable を利用することで処理を簡潔に記述しています。


<SubscribeToInteractable の場合>
        // 攻撃ボタンの状態を更新するストリーム(☆ いままで Update で処理していた内容)
        currentATB
            .Select(atb => atb >= attackThreshold)
            .SubscribeToInteractable(attackButton)
            .AddTo(this); // ストリームを破棄するために必要

 これは

<Subscribe の場合>
        // 攻撃ボタンの状態を更新するストリーム(☆ いままで Update で処理していた内容)
        currentATB
            .Select(atb => atb >= attackThreshold)
            .Subscribe(isInteractable => attackButton.interactable = isInteractable)  // この部分をSubscribeToInteractableで代用している
            .AddTo(this); // ストリームを破棄するために必要

 と同じです。


参考サイト
Qiita @RyotaMurohoshi 様
UniRxでトグルのオン・オフの変更に連動し、ボタンの有効・無効を変化させる



 これらのストリームをAddToメソッドでATBControllerに対して購読し、GameObjectが破棄されたときにストリームも破棄されるようにしています。



 このように UniRxを使用することで、ATBシステムの実装が簡単になり、コードがよりシンプルになります。
UniTaskを使用することもできますが、この場合はATB値の回復など、一定間隔で実行される処理に限定して使用することが一般的です。

 ここでの重要な点は、ストリームを活用して各機能を実装していることで、コードを簡潔かつ分かりやすくしていることです。
データの流れを明確にし、コードの読みやすさや保守性を向上させることができます。


処理の置き換え


 UniRx には多くのファクトリ・メソッドが用意されているため、同様の処理を、複数の書き方で実装出来ます。

 以下は Observable.EveryUpdate() の部分を Observable.Interval() で作成した場合のケースです。
処理の内容は同じ機能として実行されます。


      // Interval() を使って、1フレームごとにATBを回復するストリーム
    Observable
        .Interval(TimeSpan.FromSeconds(1f / recoveryRate))
        .Where(_ => CurrentATB.Value < maxATB)
        .Subscribe(_ => {
            var delta = 1f / recoveryRate;
            CurrentATB.Value = Mathf.Clamp(CurrentATB.Value + delta, 0f, maxATB);
        })
        .AddTo(this);

 ここでは Observable.Interval を使って、一定時間ごとにストリームを発行しています。

 TimeSpan.FromSeconds(1f / recoveryRate) で、1秒を recoveryRate で割った時間間隔でストリームを発行します。
その後、 Where オペレータで CurrentATB の値が maxATB 未満である場合にストリームを通過させ、Subscribe でATB値を回復させています。

 ここでは、回復量を 1f / recoveryRate で計算し、 Mathf.Clamp メソッドを使用して、ATB値が最大値を超えないようにしています。



 1回の説明を読んだだけでは理解をすることが難しい内容であるため、
実際に処理を書いて、動かしてみるようにするとよい学習になります。



 以上になります。

 続いて、クラス内の処理を分割し、MVPパターンによる実装を行います。

 次は イベント駆動型処理の作成例 です。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu



技術/知識(実装例)

2Dおはじきゲーム(発展編)

2D強制横スクロールアクション(発展編)

3Dダイビングアクション(発展編)

2Dタップシューティング(拡張編)

レースゲーム(抜粋)

2D放置ゲーム(発展編)

3Dレールガンシューティング(応用編)

3D脱出ゲーム(抜粋)

2Dリアルタイムストラテジー

2Dトップビューアドベンチャー(宴アセット使用)

3Dタップアクション(NavMeshAgent 使用)

2Dトップビューアクション(カエルの為に〜、ボコスカウォーズ風)

VideoPlayer イベント連動の実装例

VideoPlayer リスト内からムービー再生の実装例(発展)

AR 画像付きオブジェクト生成の実装例

AR リスト内から生成の実装例(発展)

private



このサイト内の作品はユニティちゃんライセンス条項の元に提供されています。

管理人/副管理人のみ編集できます