yotiky Tech Blog

とあるエンジニアの備忘録

Unity におけるアーキテクチャの予備知識

2つのパターン

Unity でアーキテクチャ、設計を考える時は異なる2つのパターンがある。

イベント駆動型プログラミングと Game Loop パターンである。

イベント駆動型プログラミングインタラクティブなシステム(GUI)で用いられるプログラミング手法である。
Win32 ではメッセージループで処理していたが、その後の .NET Framework のデスクトップアプリや Web アプリなどではそれを意識せずにプログラムを組むことができるようになった。

Game Loopデザインパターンの1つとして紹介されている。(Game Programming Patterns)
このパターンは、ゲームの進行をユーザー入力とCPUの速度から切り離すことを目的としている。

ずっと後者の環境で育ったプログラマには違和感があるかもしれない。
元々はメッセージループで処理していたもののインタラクティブなシステムではその仕組が隠蔽されたため、そちら側からは改めてデザインパターンとして名付けられたと思われる。

ゲーム

Unity はもちろん Game Loop を前提としたむき出しのゲームエンジンである。
パターンの目的を見て分かる通り、多くのゲームではユーザーの入力とは非同期的に進行し続け、CPUの速度に依存せず安定して動き続ける必要がある。
特に性能要件がシビアな場面では Game Loop 抜きではコントロールが難しいだろう。

ゲームと言ってもゲームを構成する要素にはインゲーム / アウトゲームとあり、Game Loop が必要になってくるのはインゲームの方である。
アドベンチャーやターン制のゲーム、シミュレーションなどは、インゲームであっても Game Loop の必要性がないケースもある。
また、Unity を利用していてもゲームではないものの場合、そのシステムが非同期的な進行を要するかどうかを見定める必要がある。多くの場合は不要であろう。

ゲームの範囲を超えた多くのシステムではメッセージループを意識しないレイヤーで設計がなされている。
そしてそれらを軸にアーキテクチャが語られることが多いということを一度意識しておく必要がある。

向き不向き

Game Loop をベースにした実装は、それぞれが状態を持ち、それを監視しあって相互作用する動きはマイクロサービスに近い。
そのためマイクロサービスのデメリットであるトランザクション(データの一貫性)、設計が高難度、障害解析の難しさなどは Game Loop でも同じことが言えそうである。

イベント駆動型はユーザー入力などのイベントをトリガーとして、関数の呼び出しの連鎖で一連の処理を実行する。
状態を監視する仕組みは Game Loop のようにループの中で値を監視するコードではなく、値が変わったことをイベントとして発行 / 購読するコードになる。

FPSのようなゲームでイベント駆動型プログラミングをしようとすると、同時多発的に状態変化が起きてイベントが発生し、購読した処理がまたイベントを発生させてイベント連鎖スパゲッティになることが安易に想像できる。
逆にショッピングアプリのようにユーザーの入力がないと描画の変化がないシステムで、Game Loop のような仕組みが必要かと言われるとNOである。

イベント駆動型のコードの可読性が高くなり障害解析も容易になるというメリットはアプリを保守運用していく上で決して小さくはないだろう。
どちらのパターンでも逆の実装ができないわけではないだろうが向いていない。
イベント駆動型プログラミングと Game Loop パターンはそれぞれにメリット・デメリットがあり、システム自体や機能毎に対しても向き不向きがある。

また、スクリプトの記事を呼んだり、設計や実装の話を聞いたりしたりする時はそれがどちらのことを中心にした話なのか意識すると良いだろう。