エンジニアっぽくなりたい

UnityやUnrealEngine 4などでなにか役に立ちそうなことを発信していく。

UE4レベル移動時に特定のPlayerStartから開始する方法

エディターでの作業時やどのレベルから移動してきたかに応じてレベルの開始位置を指定したい場合があると思います。
特に設定をしていないPlayerStartを複数配置したレベルに移動すると、どのPlayerStartから始まるかは実行のたびに変わります。

じゃあどうしたらいいんですか!!!


目標


レベルに移動時、どのPlayerStartから開始するかを指定できる方法を模索する。


環境

・UE 4.26.1 (エンジンビルドはしていません)


結論

いきなり結論ですが、既存のエンジンの仕組みで対応が可能です。
OpenLevelノードの「LevelName」に「[レベルのパス]#[対象のPlayerStartのPlayerStartTag]」と指定することで実現できます。

f:id:naoxgames:20210320015240p:plain
OpenLevel

手順

例として、Contentフォルダ直下に配置された「Test」というレベルに、PlayerStartが2つあるとします。

まずは配置したPlayerStartの詳細から以下にある「PlayerStartTag」に識別する名前を設定します。配置したものすべて違うものにしましょう。
ここでは「PlayerStart1」「PlayerStart2」と設定します。

f:id:naoxgames:20210320014242p:plain
PlayerStartTag

次にOpenLevelノードを配置し、「LevelName」に設定をします。

[レベルのパス]#[対象のPlayerStartのPlayerStartTag]

・レベルのパス → Contentフォルダを/Game/に置き換えたファイルのパスです。例では「/Game/Test」となります。※Test.TestとかTest.umapとかではない。

・対象のPlayerStartのPlayerStartTag → 配置されたPlayerStartに設定した「PlayerStartTag」の文字列。

f:id:naoxgames:20210320020010p:plain
OpenLevel


この設定でレベル移動してみると想定したPlayerStartから開始できるのがわかります。

調べる

処理の流れを確認してみます。
やはりエンジンコードを追うしかありませんね。。。

「OpenLevel」を探すと「GameplayStatics.cpp」にたどり着きます。
「UGameplayStatics::OpenLevel」の中を追うと「LevelName」と「Options」をコマンドとして「GEngine->SetClientTravel」に入れてます。
さらに中に行くと「Context.TravelURL」にコマンドを入れて処理が終わってます。どうなっている!?

「TravelURL」で検索すると「UEngine::TickWorldTravel」で使われている様子。
さらに追うと「UEngine::Browse」に「FURL」に変換して使っている様子。
その後「UEngine::LoadMap」→「ULocalPlayer::SpawnPlayActor」→「UWorld::SpawnPlayActor」→「AGameModeBase::Login」→「AGameModeBase::InitNewPlayer」と来て、やっと核心に迫ります。(ここまでは、それっぽいところにブレイク張って頑張って追いかけましょう。)

たどり着いたのは「AGameModeBase::FindPlayerStart」です。
ここでPlayerStartを探しています。その手掛かりに使っているのが「FURL」のメンバ「Portal」です。

ではこの「Portal」はどうやって取得しているのか、検索します。
すると「FURL::FURL」で取得しており、処理の流れを見ると、「#」の後に指定したものが「Portal」に設定されるようです。


っということで、処理の流れを追いかけて、なぜ#[PlayerStartTag]でこの挙動になるのかがわかりましたね!!
この挙動について、ネットで検索をいろいろしてみましたが驚くほど情報が出てこず、なかなか使わないのか、この方法は非推奨なのか、具体的なことはわかりませんが、とりあえずはコードを見た上でこの対応で問題ないと思われます。



正しい対応方法やより良い方法があればご指摘お願いいたします!!!