UE5 のローカルマルチプレイヤーを 1 つのデバイスで操作する

第21回UE5ぷちコン|株式会社ヒストリア で以下の作品を提出しました。

第21回UE5ぷちコン 提出動画「Hand Push Sumo」 - YouTube

ゲームを作るにあたり、さくっと遊ぶために「キーボード一つあれば遊べる」ようにしたかったので、タイトルにもある「ローカルマルチプレイヤーを1つのデバイスで操作する」方法を調べました。

簡単なローカルマルチプレイヤー

以下の2つの記事がとても参考になります。

基本的には以下の Create Local Player ノードを呼び出すだけでよく、とても簡単です。

ですがこの場合、PlayerController がプレイヤーの数だけ作成され、インプットデバイスも同様数が必要になります。
一つはキーボードでいいとしても、もう一つゲームパッド等が必要になるわけです。

キーボード一つのインプットデバイスでローカルマルチプレイヤーを構築する

GitHub - dany1468/LocalMulti1Device

今回試したコードは上記で管理しています。UE 5.3.2 で実行できます。

今回試したのは以下の3パターンです。

  • 分割無しの一つの画面
    • /Maps/SingleViewMap
  • 2分割された画面で、最初からキャラクターは配置しておく
    • /Maps/SeparateViewMap
  • 2分割された画面で、ゲーム開始時にキャラクターを Spawn する
    • /Maps/SeparateViewWithPlayerStartMap
分割無し 2分割

以下では簡単にそれぞれの方法を見ていきます。

キャラクター

上記のいずれのパターンでもキャラクターは単純なもので一つの BP (BP_PlayerCharacter) です。

プロジェクトを直接見てもらうのが早いですが、 PhysicsConstraintCubeSphere をつないでおり、Sphere が前方方向にのみ動くように設定しています。

Event Graph も単純なものです。今回の本題とは外れるので内容は省略します。

パターン1: 分割無しの一つの画面

/SingleView/PC_SingleViewPlayerController です。GameMode である GM_SingleView もありますが、Event Graph はなく Default の設定だけです。

以下が PC_SingleViewBegin Play です。

まず、ここまででCreate Local Player ノードを利用していないこと」がポイントです。つまり、PlayerController は一つしか無いということです。

次に、 SingleViewMap レベルには BP_PlayerCharacter を 2 プレイヤー分配置し、それぞれ Player1, Player2 のタグを付けてあります。

上記では、Get All Actors with Tag を使って配置してあるキャラクターを取得し、 PlayerController に保存しています。

続いて、以下が PC_SingleView の Action 部分です。

見ての通りで、 Begin Play で保存した両方のキャラクターの参照に対して Push を実行しています。

こうすることで、一つのデバイスで2つのキャラクターの対戦を実現できます。

ちなみに、Player 0 は2つのキャラクターを映すカメラに Possess させています。

パターン2: 2分割された画面で、最初からキャラクターは配置しておく

まず、PlayerController は先程と同じ /SingleView/PC_SingleView を利用しています。つまり SeparateViewMap には、同様にタグの付いたキャラクターを配置しています。

そして GameMode を変更し GM_SeparateView を用意しています。

今回は画面を分割しているので Create Local Player ノードを利用しています。

2つの PlayerController が出現することになりますが、レベルに配置済のキャラクターにはタグだけではなく Auto Possess Player にそれぞれ Player 0, Player 1 を設定し、それぞれの PlayerController に対応させています。

しかし、最終的に利用するのは 1つ目のインプットデバイスに紐づく 1 つ目の PlayerController だけです。今回のコードだと、利用しない 2 つ目の PlayerController でも Begin Play が実行されてしまいますが、利用しないのでスルーします。

パターン3: 2分割された画面で、ゲーム開始時にキャラクターを Spawn する

まず、レベル上には PlayerStart を2つ配置します。それぞれの Player Start TagPlayer1, Player2 を設定しておきます。

ここでは GameModePlayerController の両方を作成します。 GM_SEparateViewWithPlayerStartPC_SeparateViewWithPlayerStart が該当します。

操作に関してはここまでと同様で、一つの PlayerController で両方のキャラクターを操作できるようにしておきます。
重要なのはキャラクターの配置部分です。

ここは PlayerStart を利用してそれぞれのキャラクターを配置しています。
一つ前の例と違って、キャラクターの配置まで重複して実行して欲しくないので、ここのコードでは PlayerController の初期化処理を Begin Play に任せず、 GameMode から明示的に1つ目の PlayerController の初期化処理だけ呼ばれるようにしています。

まとめ

さらっとした感じでまとめましたが、この仕組みを実装する前は「インプットデバイス」と PlayerController の関係も正しく理解しておらず手法の検討もつきませんでした。

分かってしまえば「1つの PlayerController を前提に考える」だけで良かったのですが、調査をするなかでいろいろと学びもあり良かったです。