Let's Enjoy Unreal Engine

Unreal Engineを使って遊んでみましょう

UE5 Lyraサンプルゲームの設計を解説してみる

UE5の正式版がリリースされてから3週間ほど経過しました。既に色んな検証をされている方も多いでしょう。正式版のリリースノートは以下にあります。

docs.unrealengine.com

さて今回はUE5正式版リリースと同時に発表された『Lyra』と呼ばれるサンプルゲームについてです。LyraはサンプルゲームでありながらUE5の機能をフル活用しつつUE5の最新機能や設計などを学べるとても良く出来たサンプルになっています。しかしLyraの設計はその最新機能を使い倒したものとなっており、おそらくUnreal Engine上級者でもすぐに理解するのが難しい内容となっています。

今回はLyraを独自に解析して、私が理解できた部分を解説していくという内容となっています。比較的上級者に向けた内容となっているかもしれませんので、ご了承ください。Lyraサンプルゲームの公式解説は以下にあります。

docs.unrealengine.com

LyraのプラグインとGame Features

Lyraは非常にモジュール構造を意識した作りとなっており、プラグイン化された機能が非常に多くなっています。その数なんと15ものプラグイン数。

これらのプラグインは規模の小さいものも多く、一部はソースコードも含まれていないプラグインもあります。特にGame Featuresを意識して、簡単につけ外しができるようになっているプラグインが3つほどあります。Game Featuresについては以下の記事で一度解説していますので、ぜひ参考にしてください。

unrealengine.hatenablog.com

このGame Featuresを使うことで、複雑な依存関係を発生させないままで様々な機能を追加することができるようになっているようです。Lyraでは以下の3つのプラグインがGame Featuresによって、動的につけ外しができるようになっています。

・ShooterCore(シューターゲームのコアロジック部分)
・ShooterMaps(シューターゲーム用の背景やロジック以外の部分)
・TopDownArena(ボン○ー○ン風ゲームのロジックとその背景部分)

ShooterCore部分にシューターゲーム用のコアロジックが含まれています。これはあくまでもBP実装によるロジックであり、C++部分のロジックは『LyraGame』モジュール(つまりプロジェクトのモジュール)に含まれています。この実装方法がLyraを理解する上で少し混乱する原因になっているかもしれません。

しかしLyraが凄いのはSooterCoreとTopDownArenaという実質全く異なるゲームが2つ入っていますが、これはどちらもLyraGameというモジュールに含まれつつも、ShooterCoreとTopDownArenaにそれぞれのコアロジックが入っているために、お互いに全く依存関係がありません。そしてGame Featuresによって読み込まれるまでそれぞれのプラグインはメモリーにも読み込まれないので、不要なものは一切読み込まずに取り外し可能となっています。これは大規模なゲームには非常に大きい効果を持つ機能でしょう。

LyraCharacterについて

LyraCharacterは名前の通りキャラクタークラスとなりますが、様々な用途で使うために非常に抽象化されたクラスとなっています。クラスの継承関係図は以下のようになっています。

C++層ではあくまでも基礎的な『ALyraCharater』というクラスを定義しています。ここで基礎的なキャラ用の機能やGameplayAbilityシステムに対応するためのインターフェースをクラス側に設定しています。機能自体は多くありませんが、あくまでも基礎的な機能を提供しているようです。

1階層上のクラスである『AModularCharacter』クラスはほぼ『ACharacter』と変わりませんが、唯一やっていることは、Game Featuresに対応するために『Add Receiver』や『Remove Receiver』をBeginPlayやEndPlay内で実行しています。これによりLyraのキャラクターはGame Featuresによって動的に機能をつけたり外したりが実現できるようになっています。

次にBP層となる『Character_Default』クラスですが、『ALyraCharacter』をBPでラップしただけで特に何かをやるクラスというわけではなさそうです。実質上BPでのベースクラスとなっています。

『B_Hero_Default』はキャラクターとして動作するための実装されています。ただし、このクラスでやっていること自体はそこまで多くありません。実際の挙動はこのクラスから追加されている『Lyra Hero』と呼ばれるコンポーネントです。

このコンポーネントC++上で実装されており、コンポーネントでありながらも移動やカメラ操作の入力バインドを行い、最も基本的な入力操作を制御するコンポーネントとなっています。このコンポーネントがなければ基礎的な入力操作を行えないという状態になっています。

そして最後に出てくる『B_Hero_ShooterMannequin』ですが、これがシューターゲーム用のキャラクターロジックのメインクラスとなっています。これとは別に『B_Hero_Arena』という同じ階層のクラスが存在しますが、これはTopDownArenaゲーム用のキャラクターロジックのクラスです。Game Featuresによってこれらも切り替えをすぐ出来るようになっています。

B_Hero_ShooterMannequinの中身には当然ながらゲーム用のロジックが色々と存在しますが、基本的なエイム動作やダッシュなどの行動ごとのロジックは全てGameplay Ability上で実装されており、キャラクタークラス内には一切存在していません。これらのGameplay Abilityはどのクラスでも簡単に使えるように依存関係がないように実装されており、プレイヤーもAIも全て同様のロジックで動作するようになっています。

またこれらのCharacterクラス全ての最大の特徴として『Event Tick』が一切使われておらず、Tick有効化の設定である『Start with Tick Enabled』は一律でチェックが外れています。つまりLyraCharacterは全てがイベントドリブンで高速に動作するようになっているということですね。


LyraでのGameplayAbilityと入力システム

Lyraではこれまでに見たことのないレベルでGameplayAbilityが使い倒されています。非常に複雑な使い方をされているため、どのようにうまく仕組みが動いているのかを理解できない方も多いんじゃないかと思います。一番基礎的な内容を事例にして紹介しましょう。

Lyraのシューターゲーム部分であるShooterCoreプラグイン内の『Game』というフォルダー内に『AbilitySet_ShooterHero』というデータアセットがあります。このデータアセットはShooterCoreがGame Featuresによって有効化された後に、『HeroData_ShooterGame』というデータアセットが読み込まれるので、有効化されます。

このデータアセットの中には複数のGameplay Abilityと『Input Tag』というGameplayTagsによって、入力情報とそれによって発動するGameplay Abilityのアクティベート化を自動的に設定される仕組みが行われています。

画像の中には、Input Tagが『InputTag.Jump』というタグが入力された際に『GA_Hero_Jump』というGameplay Abilityがアクティベートされるように設定されています。わかりやすいですね。つまりジャンプボタンがを押した時にジャンプするGameplay Abilityが自動的にアクティベートされてジャンプが実行されるようになっています。

そもそもInputTagとは?少しわかりにくいかもしれません。これは単なるGameplayTagsの一種であり、特に特殊なものではありません。Lyraでは『InputData』と呼ばれる特殊なデータアセットで、特定の入力とInputTagを関連付けています。このInputDataは少し前から実装された新入力システムである『Enhanced Input』を使ったものとなります。Enhanced Inputは一度解説したことがありますので、こちらも参考にどうぞ。

unrealengine.hatenablog.com

Enhanced Inputでは『Input Action』と呼ばれる、入力アクションを設定することができます。

この入力アクションは『Input Mapping Context』と呼ばれる、通称入力マッピングコンテキストにより、実際にどのキーを押すことで発動するかを決めています。これはLyra内のInputフォルダーのMapingsフォルダーに存在する『IMC_Default_KBM』というキーボード用の入力マッピングコンテキストの画像です。

IA_Jumpという入力アクションがスペースバーに紐付けられていることがわかります。ここにInputDataが紐付けられている、『InputData_Hero』の中身を見てみましょう。このアセットはLyra内のInputフォルダーにあります。

Input ActionとInput Tagとが紐付けられていることがわかります。これにより『IA_Jump』のキーが押された時に『InputTag.Jump』が紐付けられたGameplay Abilityをアクティベートします。つまり『GA_Hero_Jump』というGameplay Abilityの『Event Acitivate Ability』が実行されるわけですね。

非常に複雑ではありますが、入力に対して1つのGameplay Abilityがうまく紐付けられていることがよくわかります。しかもその入力はInput ActionやInput Mapping Contextにより細かいところまでカスタマイズが可能です。これらはなんと全くお互いに関連性を持ちません。Gameplay Abilityは汎用的に扱えるので、キャラクターやゲームジャンルなども関係なく流用が可能です。

Lyraサンプルゲームの設計まとめ

Lyraを一通りみてわかったことは、UE5では大規模化を想定した依存関係のないモジュールシステムを構築しようとしていることがハッキリとわかりました。Game Featuresによって動的にモジュールを付け替えたり、Gameplay Abilityと入力システムの汎用化により、それぞれは全く依存関係は持たないままで、あらゆるジャンルやゲームプレイに対応したゲームを作れるようになっています。

これまでブループリントインターフェースなどで依存関係を抽象化していたりしましたが、それも必要なくなります。Game FeaturesやGameplay Ability、Enhanced Inputは覚えることも多く、実用できるようになるまでは時間がかかりますが、その効果は絶大です。これから大規模化していくゲーム開発にとって覚えていくことは必須になるものかと思います。

LyraのShooterCoreはかなり複雑なので、最初はもう少しシンプルな作り方をしているTopDownArenaの方を参考にしてみるとより理解しやすいかもしれません。