【UE4】Default PawnはPlayer StartのPitchとRollを無視してSpawnされるメモ

:::note info
対象バージョンはUE4.27.2です。
:::

あらかじめPlayer Startを床面に対して斜めに傾けておき、ゲーム開始時にDefault Pawn(=Player Pawn)を斜めにSpawnさせようとしたがうまく行かなかった。これを調べた結果のメモを残しておく。

# 何が起きたか？

あらかじめPlayer Startを斜めに傾けておく。
つまりPlayer StartのRotationのPitch(Y回転)やRoll(X回転)にゼロ以外の角度を入れておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/f04f38c8-a8ca-c276-51a8-5cd5655d4d79.png)
ビューポートで見るとこんな感じ(↓)になる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/b9619ba2-20bb-ed99-8a0c-252de45cd754.png)

このPlayer Startと全く同じ位置・回転を持つDefault Pawn(=Player Pawn)をゲーム開始時にSpawnしたい。
Default Pawn(=Player Pawn)の位置・回転が分かりやすいように、以下のようなPawnを作った。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/08f25fee-c861-2852-6a19-cde5d15d05ae.png)
Arrow Componentを使って座標軸を持たせただけである。
※なおArrow ComponentのHidden in Game値はデフォルトでTrueなので、あらかじめFalseにしておくことを忘れずに。

次に、このPawnをGame ModeのDefault Pawnに設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/8b6f2bbd-b416-4ae1-47d5-e4c43f568b2d.png)

この状態でゲームを実行、[F8]キーなどでEjectをしてDefault Pawn(=Player Pawn)の回転を確認するとこう(↓)なってしまう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/665813a1-8c2d-7f07-b763-386d7dc95877.png)
分かりづらいかもしれないが、

- Z軸(青)が真上を向いている方がDefault Pawn(=Player Pawn)である。
- 選択されている方がPlayer Startで、X軸(赤)がイスの方向を向いている。

つまり、Default Pawn(=Player Pawn)がPlayer Startの回転を反映していないのである。
詳細パネルでそれぞれのRotationの値を確認すると、どうやらX回転(Roll)とY回転(Pitch)がゼロクリアされているようだ。

||X回転<br />Roll|Y回転<br />Pitch|Z回転<br />Yaw|
|:----|:----:|:----:|:----:|
|Player Start|10.0|-30.8|-143.3|
|Default Pawn|<font color="red"><b>0.0</b></font>|<font color="red"><b>0.0</b></font>|-143.3|

これはそういう仕様だろうか？

# エンジンソース

エンジンソースを見てみると、Player StartのYaw回転(Z回転)のみしか使っていないコードが見つかる。コメントにも「Don't allow pawn to be spawned with any pitch or roll (PitchやRollを使ってPawnをSpawnしない)」と明記されている。
ソース内でも、StartSpot(=Player Start)のYaw回転しかコピーしていない。
…ということでこれは仕様である。

```c++:GameModeBase.cpp&#x20;(1699行目,UE4.27.2)
APawn* AGameModeBase::SpawnDefaultPawnFor_Implementation(AController* NewPlayer, AActor* StartSpot)
{
    // PitchやRollを使ってPawnをSpawnしない
    FRotator StartRotation(ForceInit);
    StartRotation.Yaw = StartSpot->GetActorRotation().Yaw;
    // 以下略：上記StartRotationとStartSpotのLocationを使ってDefaultPawnをSpawnしている。
}
```

:::note info
もちろん「たいていの場合は」プレイヤの初期回転にPitchやRollを入れることはないので、この仕様で困ることはめったにないだろう…とは思う。
:::

# 対処方法

`SpawnDefaultPawnFor_Implementation()`は末尾に"_Implementation"がついていることから推測できるように、この関数は[Blueprint Native Event][native-event]である。

[native-event]:https://docs.unrealengine.com/4.26/ja/ProgrammingAndScripting/GameplayArchitecture/Functions/Specifiers/

```c++:GameModeBase.h&#x20;(434行目,UE4.27.2)
UFUNCTION(BlueprintNativeEvent)
APawn* SpawnDefaultPawnFor(AController* NewPlayer, AActor* StartSpot);
```

なので、この関数はBlueprintでオーバーライドできる。
GameModeBaseを継承したBlueprintを作って`SpawnDefaultPawnFor`関数をオーバーライドすればすればよい。例えば次のようにすれば、Player Startと全く同じRotationを持ったDefault Pawn(=Player Pawn)がSpawnできる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/8ea4e458-2ca3-a1a7-e4f2-cdfc13777110.png)
要するに、余計なことは何も行わずに素直にSpawnするだけである。
これを実行すると、SpawnされたPawnとPlayerの回転が一致していることが確認できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/0f5e75cc-b688-f423-5d64-2872e038da07.png)

# 追記

なお、Player Controllerの回転値も似たような制約を受けている。ただしRoll(X回転)だけ。
これが行われるのは２か所で、いづれもゲームの初期化時(最初のBegin Playより前)である。

- AGameModeBase::InitNewPlayer()内 (GameModeBase.cpp 753行目, UE4.27.2)
    - Player ControllerがSpawnされた後、Player StartのRoll(X回転)だけゼロにした回転を SetInitialLocationAndRotation()でセットされている。
- AGameModeBase::FinishRestartPlayer()内 (GameModeBase.cpp 1320行目, UE4.27.2)
    - Default Pawn(=Player Pawn)がSpawnされた後、Spawnの最終処理として行われる。
    - Player Controllerの<font color="red"><b>Control Rotation</b></font>として、Default Pawn(=Player Pawn)のワールド回転のRoll(X回転)だけゼロにした回転をSetControlRotation()でセットされている。

----

以上です。