Unityに関連する記事です

 前回に続いて、ReactivePropery を活用した処理の実装を行います。
 
 ここでは GameManager クラスと、それと依存関係にあるクラスの処理を順番に見直していきます。


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


 以下の内容で順番に実装を進めていきます。

発展2 −UniRX (ReactivePropery)を利用した処理の実装 
4.クラス間の依存関係の見直し



 新しい学習内容は、以下の通りです。

 ・クラスの依存関係と疎結合
 ・UniRX のオペレーター機能の実装例  Where メソッドー
 ・UniRX の基本動作  Dispose メソッドー



4.クラス間の依存関係の見直し

1.設計


 GameManager クラスと、その他のクラスとの間の依存関係について考えて、解消できる部分については依存関係を解消して、クラスの独立性を高めます。

 最初に、現在の GameManager クラスと JobsConfirmPopUp クラスの関係を見ていきます。

<クラス間の依存関係>
 GameManager クラス ⇔ JobsConfirmPopUp クラス

 GameManager クラスは、JobsConfirmPopUp クラスをプレファブの情報として管理しており、インスタンスする処理を担当しています。
その際に、JobsConfirmPopUp クラスの SetUpJobsConfirmPopUp メソッドを実行し、GameManager クラスの情報を提供しています。

 そのためこれは、お互いがお互いを知っており、つながっている、依存している関係であると言えます。

参考サイト
Qiita @wm3 様
プログラムの依存関係とモジュール構成のこと
https://qiita.com/wm3/items/2c90bfd9e973d368ebd8


 こういった設計の場合、どちらか一方の変更により、もう一方の処理が上手く制御できなくなる恐れがあります。

 そのため、可能であれば、単一方向の依存関係に修正することにより、1つのクラスの独立性が保たれることにより、依存関係が薄くなり、疎結合化することが出来ます。

<やりたいこと その 
 GameManager クラス → JobsConfirmPopUp クラス(GameManager クラスだけが JobsConfirmPopUp クラスを知っている)

<やりたいこと その◆
 GameManager クラス ← JobsConfirmPopUp クラス(JobsConfirmPopUp クラスだけが GameManager クラスを知っている)

 前回の手順で実装を行った ReactivePropery の場合も同じで、GameData クラスのことを UIManager クラスだけが知っている状態(単一方向)になっています。
そのため、お互いに依存しあうことなく、処理の実装が実現出来ています。



 今回の実装も同じように考えます。
いままでは依存しあっていたクラスを片方だけが相手のクラスのことを知っている状態に作り変えます。

 まずは JobsConfirmPopUp クラスの独立性を高めて、GameManager クラスのことを「知らない」状態にします。
その代わりに、ReactivePropery を準備して、JobsConfirmPopUp クラスで発生した状態を外部のクラスに通知できる状態に変えます。

 そして、GameManager クラスでは JobsConfirmPopUp クラスの情報を ReactivePropery を通じて知る(監視)するように変更を行います。

 ReactivePropery は、値に変化があった場合に、購読者(GameManager クラス)に対して、通知を発行します。
そのタイミングで、GameManager クラスは予め用意しておいたメソッドを実行する設計です。


2.JobsConfirmPopUp スクリプトを修正する


 using に宣言を追加して、ReactivePropery を利用できるように追加します。

 GameManager クラスとの依存関係を解消するため、OpenPopUp メソッドの第2引数で受け取っていた GameManager クラスの情報を削除し、受け取らないようにします。
これで JobsConfirmPopUp クラスは GameManager クラスを「知らない」状態になります

 ClosePopUp メソッドを修正し、ReactivePropery の値に対して、選択したボタンの種類に応じて、true か false かで代入を行います。
この値の変更が発生するタイミングで、GameManager クラス側に通知が届き、GameManager クラスが自動的に用意してあったイベント(メソッド)を実行します。

 以上のような設計に変更することにより、JobsConfirmPopUp クラスは、自分の中だけで行う処理のみになり、独立性が高くなるとともに、
このクラスから外部クラスへの呼び出し命令もなくなるため、スクリプト同士の依存関係がなくなり、スクリプトの可読性も上がるようになります。


JobsComfirmPopUp.cs

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


 スクリプトを修正したらセーブします。


3.GameManager スクリプトを修正する


 JobsConfirmPopUp クラスをインスタンスする際の処理に修正を行います。

 インスタンスした後に実行する OpenPopUp メソッドでは、第2引数を削除して、GameManager クラスの情報を渡さないようにします。
これはすでに JobsConfirmPopUp クラス側でも設定済です。

 続いて、JobsConfirmPopUp クラスに追加した ReactivePropery の監視処理を追加します。

 ここでも監視処理は一度実行すれば、あとはずっと監視状態になります。
非同期処理になるため、JobsConfirmPopUp クラスのインスタンスを保持しておく必要もありません。

 この ReactivePropery は JobsConfirmPopUp クラスで制御しているいずれかのボタン処理が実行されて ClosePopUp メソッドが実行されたときに
値の更新が実行されるので、そのタイミングで、イベントが発生し、Subscribe メソッドに指定されている JudgeSubmitJob メソッドが実行されます。

 この設計により、GameManager クラスのみが、JobsConfirmPopUp クラスを知っていて監視している状態を作りだすことが出来ます。

<やりたいこと その 
 GameManager クラス → JobsConfirmPopUp クラス(GameManager クラスだけが JobsConfirmPopUp クラスを知っている)


GameManager.cs

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


 スクリプトを修正したらセーブします。


4.<UniRX のオペレーター機能の実装例  Where メソッドー>


 UniRX にはオペレーターというフィルタリングを行う機能があります。
オペレーターには多くの機能がメソッドとして用意されているため、それをメソッドチェーンを利用し、フィルタリングを行って、その結果を受けて次の処理を実行することが出来ます。

 Where メソッドもオペレーターの1つです。引数に指定した情報に対してフィルタリングを行います。

 Where メソッドの引数内に条件式を記述し、その条件式を満たしたメッセージ(今回であれば ReactivePropery の値)を通過させることによって、通知を実行します。
そのため、ReactivePropery の値が変更されただけでは通知は実行されず、Where メソッドの条件式を満たしたときだけ、次の処理を実行する、というフィルタリングを行うことが可能になります。

  // JobsConfirmPopUp クラスの ButtonReactivePropery を監視し、true になったときだけ、JudgeSubmitJob メソッドを実行する
  jobsConfirmPopUp.ButtonReactiveProperty.Where(x => x == true).Subscribe(x => JudgeSubmitJob(jobsConfirmPopUp.ButtonReactiveProperty.Value, tapPointDetail, -1, jobsConfirmPopUp));

 今回の場合には、Where メソッドの引数に「ReactivePropery の値(x)が、true の値である」を条件として設定しています。
そのため、ReactivePropery の値が更新されてメッセージが発行されたときに、この条件式を満たしている場合(true)のみ、次の Subscribe メソッドが実行されるようになっています。

 UniRX はこのように、日本語のコメント書式のイメージに近い内容でプログラムを記述することができるため、可読性の高いコードで実装していくことが出来ます。


5.<UniRX の基本動作  Dispose メソッドー>


 UniRX ではメッセージの発行元をストリームソースといいます。今回であれば、ReactivePropery がストリームソースとなります。
 
 ストリームソースを購読、つまり、ReactivePropery の監視を行う場合、その処理は途中で終了することなく、ずっと動き続けます。
そのため、動き始めたストリームソースに対しては、適切なタイミングで破棄する処理を実装しないと、見えない部分で動き続けていることにより
予期せぬ部分でエラーが発生したり、メモリのリークを引き起こす原因になります。

 Dispose メソッドは、このストリームソースの処理を破棄する命令になります。

 // ButtonReactivePropery の Subscribe メソッドの購読を停止する
 jobsConfirmPopUp.ButtonReactiveProperty.Subscribe().Dispose();

 今回のケースでは、Subscribe メソッドに対して破棄する命令を実行しています。
そのため、この処理以降は、メッセージが発行(ReactivePropery の値が更新)されても、Subscribe メソッド内に指定していた処理が動かなくなります

 注意点としては、Dispose メソッドを実行する対象です。

 今回のように Subscribe メソッドに対して Dispose メソッドを実行した場合、Subscribe メソッドは破棄されますが、
ReactivePropery に対して行っていないため、再度、同じ ReactivePropery から購読する処理を再開することが出来ます。

 // ButtonReactivePropery の購読を停止する
 jobsConfirmPopUp.ButtonReactiveProperty.Dispose();
 
 これに対して、上記のように ReactivePropery 自体に Dispose メソッドを実行すると、ReactivePropery 自体の処理が破棄されます。
この場合、再度購読処理を実行しても、ReactivePropery 自体が破棄されているため、購読処理を再開することが出来なくなります

 これが大きな違いになりますので、状況に応じて破棄する方法を考えていく必要があります。


6.ゲームを実行して動作を確認する


 今回の実装もリファクタリングになりますので、ゲーム上の処理は今までと同じように正常に動作している必要があります。


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

コメントをかく


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

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

Menu



プログラムの基礎学習

コード練習

技術/知識(実装例)

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

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

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

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

レースゲーム(抜粋)

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

3D脱出ゲーム(抜粋)

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

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

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

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

3Dトップビューアクション(白猫風)

VideoPlayer イベント連動の実装例

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

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

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

private



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

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