Unityに関連する記事です

 デリゲートの実装方法について、活用事例を含めて紹介します。
ダイアログ(ポップアップ)内から外部クラスにある処理を制御する際に、デリゲートを利用した実装例です。

 今回の場合、複数のボタンに情報を管理させ、それをダイアログ内で選択し、そのボタンに紐づく情報を外部クラス側に提供する処理を作成しています。

 前回の記事はこちらになります。

  => デリゲートの実装例
  => デリゲートの実装例



事前学習


 実装には UniRx を利用します。

 デリゲート、およびラムダ式による記述書式については、事前に理解しておく必要があります。
下記の教材を参考にしてください。

  => デリゲート
  => デリゲートとラムダ式の関係
  => デリゲートとラムダ式の活用事例


設計


 ダイアログ(ポップアップ)を制御する際にデリゲートを利用した実装例です。
最初の教材で提示した図を再掲載します。





 具体的な実装内容としては、メソッドの引数にデリゲートを活用することで、
ダイアログ側では管理側との依存関係を持たず、管理側のメソッドを実行することが可能になります。

 今回の場合、複数のボタンに情報を管理させ、それをダイアログ内で選択し、そのボタンに紐づく情報を外部クラス側に提供する処理を作成しています。


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


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


 特にこのような設計の際に、デリゲートが大変役立ちます。
なぜなら、ダイアログの制御クラスが、そのクラス内での情報を外部クラス(ここでは管理クラス)に提供するには、
必然的にクラス間には依存関係の構築が必要になるためです。

 ですが、デリゲートを利用することで、疎結合状態を保ったまま、ダイアログ内で作成した情報を管理クラス側に提供できることになります。


ダイアログ内のボタンの作成


 ダイアログ内に生成するためのボタンを作成し、プレハブにしておきます。
作成するボタンの形状などは任意です。

 ここではサンプルとして、各ゲームオブジェクトの画像を紹介します。










 ボタンについては、ダイアログ内の GridLayoutGroup にてサイズを調整しています。





ButtonBase クラスの作成


 先ほど作成したボタンのプレハブにアタッチして利用するクラスです。


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




 プロパティや UniRx による購読処理を利用しています。

 ボタンの購読処理はこのクラス内ではなく、別のクラスにて設定をする設計です。
これにより、柔軟なボタン処理が実装できます。


DialogBase クラスの修正

 
 DialogBaseクラスを修正し、複数の変数を定義します。

 ボタンのプレハブをアサインする変数、ボタンを生成する位置をアサインする変数の他、
生成したボタンを管理するための変数などを定義します。

 また IObservable<ItemData> 型の OnItemButtonClickAsObservable 変数を定義し、
生成したボタンに対して購読する機能を追加しています。

 このボタンの処理についても、ボタン側(ButtonBase)は直接的に外部クラスの参照を持たずに処理が実行できるため、
依存関係がない(疎結合)状態が維持できています。


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




 OnEnterOpen メソッド内の処理を修正し、ボタンの生成処理と、各ボタンに情報を設定しています。
各ボタンは ItemData と紐づいており、それらの情報はボタンごとに異なる ItemData になっています。
そのため、ボタン1は ItemData 1、ボタン2は ItemData 2 という状態です。

 PlayCloseDialog メソッド内にある DOTween の OnComplete メソッド内の処理を修正し、
新しく作成した2つ目の OnExitClose メソッドを実行するように変更されています。

 これにより、OnExitClose メソッドには引数として、ボタンにより選択されている情報が渡されます。

 新しい OnExitCloseメソッド内の処理はいままでの OnExitClose メソッドと同様ですが、
こちらでは引数付のデリゲートである onCloseActionItemData?.Invoke(itemData)では、引数に固定値ではなく、変数が指定されます。
それにより、ボタンに紐づいている情報が、外部クラスに対して提供されるように変更されています

 このような設計にしておくことで、ダイアログ内で押されたボタンに紐づいた情報が、外部クラスに対して提供される仕組みが実装されます。


<UniRx の処理の解説>


 このコードは、UniRxを使用してボタンのクリックイベントを監視し、ボタンごとに関連付けられたItemDataオブジェクトを発行するための処理を行っています。

    public IObservable<ItemData> OnItemButtonClickAsObservable => buttonList
        .Select(buttonBase => buttonBase.OnButtonClickAsObservable.Select(_ => buttonBase.ItemData))
        .Merge();

 以下にコードの詳細な解説を提供します。


1.OnItemButtonClickAsObservable プロパティ

public IObservable<ItemData> OnItemButtonClickAsObservable =>

 IObservable<ItemData> 型のプロパティです。参照先にはラムダ式を用いた省略記法を用いており、 get のみを持つプロパティです。
このプロパティは、ボタンがクリックされたときにItemDataオブジェクトを発行するためのObservableを提供します。


2.処理の内容

 buttonList
   .Select(buttonBase => buttonBase.OnButtonClickAsObservable.Select(_ => buttonBase.ItemData))
   .Merge();

 buttonList というリスト内の各 buttonBase に対して、以下の処理を行います。

 buttonBase.OnButtonClickAsObservable は、buttonBase に関連付けられたボタンのクリックイベントを監視するIObservable<Unit>を表します。
ボタンがクリックされるたびにUnit(何もない値)が発行されます。そのため「ボタンが押された」という通知のみを行うことになります。

 .Select(_ => buttonBase.ItemData) は、buttonBase 内の ItemData オブジェクトを選択します。
ボタンがクリックされるたびに、それに関連付けられた ItemData オブジェクトが選択されます。

 .Merge() メソッドでは、Select メソッドによって生成された IObservable<ItemData> のシーケンスを、すべてのボタンのイベントを結合して単一のObservableに変換します。
つまり、各ボタンのクリックイベントが発行された順序に応じて、関連付けられた ItemData オブジェクトが単一のObservableで発行されます。

 以上のことから、このコードは、複数のボタンを管理し、それぞれのボタンが異なるItemDataオブジェクトを持つ場合に、
ボタンごとにクリックイベントと関連付けられたItemDataオブジェクトをトラッキングおよび処理するために使用されます。

 このような処理は、ユーザーが複数のアイテムから選択する場面や、異なる操作が必要な複数のオブジェクトが存在する場面で効果的です。


解説


 今回は DialogManager クラスへの修正はありません。すでに引数を用意して実行できるメソッドがありますので、ダイアログ側の修正のみで済んでいます。

 UnityAction<ItemData> のデリゲートをさらに活用し、ここに SetUp メソッドの引数として DialogManager クラスから渡ってきているメソッドの参照を保持する部分は同じですが、
この処理を実行する際に、固定の ItemData ではなく、ボタンに紐づいた ItemData を変数として指定することにより、
「ダイアログ内で押されたボタンの情報」を DialogManager クラス側に提供することが可能になっています。

 このような設計にすることで、ダイアログ側は管理側である DialogManager クラスへの依存関係を持たずに、DialogManager 内にあるメソッドを実行する仕組みが構築でき、
かつ、DialogManager クラスは外部クラスによって提供される情報を元に、新しい処理を作成していくことが可能になります。


まとめ


 前回と同じように引数付のデリゲートを使用することにより、外部クラスとのコミュニケーションをより効果的に実現し、クラス間の疎結合性を保持しています。
この引数に対して変数を利用することで、固定化された情報ではなく、その都度、必要となる情報を受け取ることが出来ます。

 また DialogBaseクラスはダイアログの基底となる処理になるため、
これを親クラスとして子クラスを作成することで、異なるダイアログに再利用可能です。
また外部クラスからカスタマイズできるため、汎用性が高いです。

 特に外部クラスの処理をデリゲートとして制御できるため、任意のタイミングで処理を実行できる部分もあり、実用性が高い設計になっています。



 以上でこの教材は終了です。

  => 次は デリゲートの実装例 です。

コメントをかく


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

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

Menu



技術/知識(実装例)

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

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

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

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

レースゲーム(抜粋)

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

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

3D脱出ゲーム(抜粋)

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

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

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

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

VideoPlayer イベント連動の実装例

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

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

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

private



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

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