【ゲーム制作】ゲーム内イベントの実装について
皆さんこんにちは!
ご閲覧いただきありがとうございます。
ゲームで必ず必要になるものが《イベント》ですよね。
そしてそれには必ず《通知》が付随します。
ここをどう管理するかが特に悩みどころであり、特に最初のうちはあちこちからイベントが飛び交いがちです。
そんなイベント周りについて、今作での工夫を書きたいと思います。
開発環境
・Unity
イベントで何が必要?
《イベント》と一言で表しても中身はゲームにより様々ですよね。
今作のインゲームでは
・敵の生成
・ADVイベントの割り込み
・宝箱の取得
・etc
などのイベントが必要になっています。
これらの要件をざっくりと考えてみます。
●敵の生成
・生成リクエストが来たら敵を出して欲しい
・設定時間が来たら設定してある敵を出して欲しい
●ADVイベントの割り込み
・ADVを特定のタイミングで起こしたい、敵の動きは止めたい
●宝箱の取得
・敵の動きを止めて演出と取得アイテム選択画面を出したい
●単独でそれぞれのイベントが動くかチェックしたい
なるほど、では敵の生成から作っていきましょう。
問題点
(2分で書いたクソコード)
"Manager"にPublicで「SpawnEnemy」という関数を用意。
"Manager"はSerializeFieldからAttachして渡します。
そこに敵の種類を指定すれば"EventManager"が敵を出現させるというものです。
動くことは動きますが、これが使えるのはプロトタイプ版くらいで後々色々と要求される事を考えると耐えられません。
何が問題かを考えてみます。
●Managerというクラス名
~Managerは「管理者」という意味でよく使われますが、Managerが増えすぎることで結果的に"何の管理者"か分からなくなる為、あまり好ましくありません。できればもっと詳細な命名をしたいところです。
●InstanceをAttachしている
Unityでたまに起きてしまうAttachしていたものが外れる問題。
これを防ぐためにAttachではなくコード内でInstanceして扱う方が良いと考えました。
●EventManagerが「直接敵を生成する」
イベントの管理クラスは《直接何かをしてはいけません》
コード量が膨大になりますし、複数人での作業もし辛くなりますよね。
●UnityのUpdate関数内で検知してイベントを呼び出している
Update関数は毎フレーム実行される処理なのでここに処理をたくさん書くことはやめます。
可能であれば《UnityのMonoBehaviourクラスは継承しない》ことでより軽量なScriptとできますね。
(最終的にGUI周りのクラス以外はMonoBehaviourを継承しなくなります)
ではこちらを踏まえて再度じっくり実装します。
今作のイベント実装
命名はEventHandlerとすることにしました。
イベントを受け取って動作するタイプのクラスに私はよくHandlerと名付けます。
今回は進行管理のような複雑なフラグ管理は不要なので「イベントのリクエストをただ登録先に受け流すもの」としました。
UniRxを用いてイベントの登録と発行を実施しています。
EventHandler.Instanceまで辿り着けば"ほぼ全てのイベント"に関与できる実装なのでやや危ないですが、発行者はデバッグで見つけやすいですし不正対策はしないのでヨシ!とすることにしました。
経過時間によって発動するイベントは、タイマー管理しているクラスに"ReactiveProperty型"で変数を用意。
値が変わった際に発行されるイベントとしてEventHandler.OnTimeChangedを登録しています。
OnTimeChanged内では"Handler"に登録されてあるイベントをPriorityでソートして実行クラスに通知します。
これらの工夫によってイベント管理クラス内でのUpdate処理は不要としています。
他にもゲーム一時停止(Pause)の管理やテスト実行用機能等の実装はしていますが大部分はお伝えできたのかなと思います。
長くなりましたが今回は以上となります!
最後まで見て頂きありがとうございます!