Unityに関連する記事です

イベント駆動型処理


 イベント駆動型プログラミング、イベントドリブンともよばれる、プログラミング手法の1つです。


参考サイト
https://e-words.jp/w/%E3%82%A4%E3%83%99%E3%83%B3%E...



 例えば、「スイッチを押したら → 扉が開く」、「ボタンを押したら → ジャンプする」という形で
「なにかをしたら(イベント) → どうなるのか(イベントハンドラ)」という形式のサイクル
イベント単位で処理が完結するように記述する方式のことをいいます。

 イベント処理自体は event キーワードや delegate キーワード(UnityAction)を活用しても作成できますが、
UniRx の機能とオブザーバーパターンを利用することでも、イベント駆動型処理を実装することができます。

 ただし、ゲーム内のすべての処理がこの処理に適しているという訳でありません。
そのため、実装する際にはどういった処理を作りたいのかを考えて、その上でどの機能(UniRx なのか、UnityAciton なのか、UnityEvent なのか)を採用するか検討する必要があります。

 基本的には、先ほどのようなボタンやクリックなどのイベントには、UniRx とオブザーバーパターンを利用すると実装しやすいです。


サンプル


 「ボタンを押す → 乱数を1つ決める」というイベントとイベントハンドラを駆動させるケースのサンプルです。


Example.cs

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




 この例では、変数の値の変更をReactivePropertyを使って監視しています。
ReactivePropertyは、値の変更があった場合に自動的に通知してくれる仕組みを持っています。

 Subscribe()メソッドで変数の変更を監視し、値が変わった際に実行する処理を記述しています。

 また、ボタンのクリックを監視し、ボタンが押された際に変数を確定させるようにしています。
variable.ValueでReactivePropertyの値を取得・設定することができます。



 UnityとUniRxを使った場合、SubscribeしたObservableのライフサイクルを管理する必要があります。
これは、Observableがアクティブな間、メモリリークを避けるためです。

 そのため、SubscribeしたObservableのライフサイクルを自動的に管理するために、通常AddToメソッドを使用します。
AddToメソッドは、Observableが終了したときに、自動的にDisposeすることができるため、メモリリークを防止することができます。

 このケースにおいても、どちらのSubscribe には AddTo メソッドを使用し、Observableのライフサイクルを自動的に管理しています。


サイコロを振るイベント


 先ほどの例を元に、「ボタンを押す → サイコロを振って出目を決める」というイベント処理の実装例です。


DiceRoller.cs

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




 Random.Range()メソッドを使用して、サイコロの目やカードの種類をランダムに決定しています。
また、それぞれの結果をReactivePropertyで保持しています。
Subscribe()メソッドで変更を監視しているので、diceResultが変更されるたびに、デバッグログに結果を出力するようにしています。


カードを1枚引くイベント


 同じように、今度は「ボタンを押す → カードを1枚引く」というイベント処理の実装例です。
こちらにはボタン連打防止の処理も追加しています。


CardDealer.cs

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




 Random.Range()メソッドを使用して、カードの種類をランダムに決定しています。
また、それぞれの結果をReactivePropertyで保持しています。Subscribe()メソッドで変更を監視しているので、
cardResultが変更されるたびに、デバッグログに結果を出力するようにしています。

 ThrottleFirst オペレータを利用することで、ボタンの連打防止を行っています。


役割に合わせてクラスを分割する


 DiceRoller クラスを役割に合わせてクラスを分割した例です。



DiceRollerInput.cs

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




DiceRollerObserver.cs

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




 DiceRollerInputクラスはサイコロを振る入力を担当し、DiceRollerObserverクラスはサイコロの結果を監視する処理を担当しています。
これらのクラスは共通の diceResult 変数を使用しています。

 DiceRollerInputクラスでイベントを受け取り、diceResult変数に結果を設定して、
DiceRollerObserverクラスでは、その diceResult 変数を監視することで、
分割されたクラスでもサイコロを振る処理が正常に動作します。

 このようにクラスを分割することで、入力と監視処理を明確に区別し、コードの可読性や保守性が向上します。


役割に合わせてクラスを分割する

 
 先ほどの DiceRoller クラスを見ながら、CardDealer クラスを、役割に合わせて複数のクラスに分割してみてください。



 それが出来たら、応用編として、カードの枚数を増やすため、string 型ではなく int 型で52枚のカード(トランプを模して)を管理して、利用してみてください。
そしてカードを引くたびにその番号のカードを抜いていき、同じ番号は引かないようにしてみましょう。

 この方法を実装すると、重複しない番号のカードが1枚ずつ山札から減っていき、最後は引くカードがなくなってデッキの残り枚数が 0 になる機能が実装できます。



 <応用編 回答例>




 以上になります。

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



参考サイト
Qiita @toRisouP 様
2022年現在におけるUniRxの使いみち
Zenn Rinia 様
神経質が設計にこだわりすぎた失敗談 〆拱化しすぎ
note REALITY 株式会社 様
Now in REALITY Tech #34 転生したらAndroidエンジニアだった件 - 元Unityエンジニアの思うゲームとアプリの技術類似点
slideshare Koji Morikawa 様
RPGにおけるイベント駆動型の設計と実装

コメントをかく


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

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

Menu



技術/知識(実装例)

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

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

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

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

レースゲーム(抜粋)

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

3D脱出ゲーム(抜粋)

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

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

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

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

VideoPlayer イベント連動の実装例

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

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

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

private



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

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