【UE4】Player ControllerのAuto Manage Active Camera Targetとは何か？

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

Player Controllerの詳細パネルを見ると"Auto Manage Active Camera Target"なるBoolean値がある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/1c4ddb5d-7b44-aea7-024d-cfd3b4d17eff.png)
この値が何者なのかをエンジンソースを追って調べてみたのでメモを残しておく。

# エンジンソースより

## APlayerControllerのメンバ変数 bAutoManageActiveCameraManager (bool型)

Player Controllerのbool型メンバ変数`bAutoManageActiveCameraTarget`の上に書かれたコメントにはこう(↓)書かれている。(詳細パネル上でマウスをホーバーしたときのヒントテキストと同じ)

:::note info
True to allow this player controller to manage the camera target for you, typically by using the possessed pawn as the camera target.  Set to false if you want to manually control the camera target.

trueにするとこのPlayer Controllerがカメラターゲットを管理してくれる。よくある例はPossessされたPawnをカメラターゲットに使う場合など。手動でカメラターゲットをコントロールしたい場合はfalseにする。
:::

## APlayerControllerのメンバ関数 AutoManageActiveCameraTarget()

この`bAutoManageActiveCameraTarget`変数を使っているのはメンバ関数`AutoManageActiveCameraTarget()`である。
関数のプロトタイプは以下のような感じ：

```c++:PlayerController.cpp&#x20;(450行目,UE4.27.2)
void APlayerController::AutoManageActiveCameraTarget(AActor* SuggestedTarget);
```

この関数は以下のような動作をする：
※`bAutoManageActiveCameraTarget`がtrueのときのみ処理をする。falseの時は何もしない。

1. レベル(≒World)に置かれたCamera Actorのうち"Auto Activate For Player"がセットされたカメラを探す。
1. そのCamera ActorのAuto Active For Playerの値が、Player Controllerのインデックス(いわゆるPlayer Index)と一致する場合は、このCamera ActorをView Targetとする。
1. 条件に合うCamera Actorがないときは、引数`SuggestedTarget`で与えられたアクタをView Targetとする。

つまり、Auto Active For PlayerをセットしておいたCamera Actorを置いておけば、自動的にそれをプレイヤーカメラとして設定してくれる機能のようだ。

## ACameraActorのメンバ変数AutoActivateForPlayer (EAutoReceiveInput型)

上記の通り、Player ControllerのAuto Manage Active Camera Targetの機能は、レベルに置かれたCamera ActorのAuto Activate For Playerを調べる。この変数はCamera Actorの詳細パネルから設定ができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/62b91ca7-38fc-6129-6dbf-3eb3497af520.png)

デフォルト値は"Disabled"。これを"Player 0"に変えて実行すると、自動的にそのCamera ActorがView Targetになってくれる。

# なんか思ったのと違う動作をする…

試してみたところ、この機能は思っていたのと違う動作をする。具体的には下の表のとおり。

||PlayerController<br />AutoManageActiveCameraTarget|CameraActorの<br />AutoActivateForPlayer|どのアクタがViewTargetになったか|
|:----:|:----:|:----:|:----:|
|①|<font color="blue">False</font>|<font color="blue">Disabled</font>|<font color="blue">Player Pawn</font>|
|②|<font color="blue">False</font>|<font color="red">Player 0</font>|<font color="red">Camera Actor</font>|
|③|<font color="red">True</font>|<font color="blue">Disabled</font>|<font color="blue">Player Pawn</font>|
|④|<font color="red">True</font>|<font color="red">Player 0</font>|<font color="red">Camera Actor</font>|

上の表は横に見る。例えば①番は「Player ControllerのAuto Manage Active Camera Targetを<font color="blue">false</font>」かつ「レベルに置かれたCamera ActorのAuto Activate For Playerを<font color="blue">Disabled</font>」にして実行した際、View Target(≒カメラ)として選ばれたアクタは「<font color="blue">Player Pawn</font>」だった、ということである。
この表でわかることは：

- 実際のView Target(≒カメラ)の選定には、Camera ActorのAuto Activate For Playerの設定しか影響していない

と言うことである。つまり、Player ControllerのAuto Manage Active Camera TargetをTrueにしようがFalseにしようが関係ないのである。これはややこしい。
これについてもエンジンソースを調べてみた。

## ACameraActorの挙動

Camera ActorのAuto Activate For Playerの挙動はBegin Playに書かれている。
ざっくり挙動を抜粋すると以下のダミーコードのような動きをする。

```c++:CameraActor.cpp&#x20;112行目,UE4.27.2
void ACameraActor::BeginPlay()
{
    if (AutoActivateForPlayer != EAutoReceiveInput::Disabled/*他の条件省略*/)
    {
        const int32 PlayerIndex = GetActivatePlayerIndex();

        // Worldのauto-activateカメラリストに登録する
        GetWorld()->RegisterAutoActivateCamera(this, PlayerIndex);

        // PlayerIndex番目のPlayerControllerにViewTargetとして設定する
        if (APlayerController* PC = UGameplayStatics::GetPlayerController(this, PlayerIndex))
        {
            PC->SetViewTarget(this);
        }
    }

    Super::BeginPlay();
}
```

この関数でやっていることは：

- Auto Activate For Playerが設定されている場合は、WorldのAuto-Activateカメラリストに自分を登録する。
- Player ControllerのSetViewTarget()を使って、自分をView Targetに設定する。
    - 注意したい点は、Player ControllerのAuto Manage Active Camera Targetの値に関わらず、つまりPlayer Controller のAutoManageActiveCameraTarget()関数を使わず、直接this(=このCamera Actor)をView Targetとして設定しているということである。

## Auto Manage Active Camera Targetの挙動

それではAutoManageActiveCameraTarget()の挙動はどうか。ブレークポイントを置いて確認したところ、次のような動きをした。

:::note warn
PIEでしか確認していません。
exeでどうなるかなどは未検証ですので、鵜呑みにはしないでくださいませ。
:::

### ゲームの初期化

まずはゲームの初期化時の挙動について。以下はUWorld::SpawnPlayActor()からの一連の呼び出しの概要：

ここではPlay用のアクタのSpawnを行っている。(Player Controller, Spectator Pawn, Player Pawn(=Default Pawn)など)

<dl>
<dt>① AGameModeBase::Login()の流れ</dt>
<dd>Player ControllerとPlayer Camera ManagerのSpawnが行われる。<br />
AutoManageActiveCameraTarget()は使われず、SetViewTarget()でPlayer Controllerがデフォルトの(最初の)View Targetとして設定される。</dd>
<dt>② APlayerController::SetPlayer()の流れ</dt>
<dd>Spectator PawnのSpawnが行われ、View TargetがSpectator Pawnに変わる。<br />
全てAutoManageActiveCameraTarget()関数でView Targetの設定が行われる。</dd>
<dt>③ AGameModeBase::PostLogin()の流れ</dt>
<dd>Player Pawn(=Default Pawn)のSpawnが行われ、View TargetがPlayer Pawnに変わる。<br />
全てAutoManageActiveCameraTarget()関数でView Targetの設定が行われる。</dd>
</dl>

### 最初のBeginPlay

以上のゲームの初期化が終わった直後に、UWorld::BeginPlay()の呼び出し(最初のBeginPlay)が行われれる。ここでは、あらかじめレベルに置かれていたアクタやここまでにSpawnされたアクタのBeginPlayが呼び出される。
つまり、Auto Activate For Playerが設定されたCamera ActorのBegin Playもここである。

## 何が問題か？

上のACameraActorの挙動で書いたように、<font color="red"><b>Auto Activate For Playerが設定されたカメラがWorldのAuto-Activateカメラリストに登録されるのはBegin Playの時</b></font>であった。
一方、Player ControllerのAuto Manage Active Camera Targetが呼び出されるのは、ゲームの初期化の流れ、UWorld::SpawnPlayActor() の時である。これは<font color="red"><b>ゲームの初回のBegin Playより前のタイミングなので、当然WorldのAuto-Activateカメラリストには何も登録されていない。</b></font>したがって、Auto Manage Active Camera TargetでAuto-Activateなカメラを検索しても何も見つからないのである。

これがAuto-Activeなカメラを設定する際に、Player ControllerのAuto Manage Active Camera Targetが影響しない原因だと思われる。

## ゲームの初期化時以外はどうか？

ここまでに書いてきた内容はすべて、ゲームの初期化からゲーム初回のBeginPlayに至るまでの流れの中の話である。ではそれ以降、プレイ中のAuto Manage Active Camera Targetの動きはどうか。
エンジンソースを"AutoManageActiveCameraTarget"で検索してみた結果、以下の関数がヒットした。

- APlayerController::ClientRestart()
    - 実装は ClientRestart_Implementation() にある。
- APlayerController::OnPossess()
- APlayerController::ClientCommitMapChange()
    - 実装は ClientCommitMapChange_Implementation() にある。
- APlayerController::SetPawn()
- APlayerController::SetSpectatorPawn()
- APawn::PawnClientRestart()
- APawn::OnRep_Controller()

ここからわかることは：

- 定期的に(Tickなどで)AutoManageActiveCameraTarget()が呼び出されているような場面はない
- 基本的には、初期化時に使われる関数群である。

と言うことである。
一方、この中で実行時にも呼び出される可能性が高いものは<font color="red"><b>OnPossess()</b></font>だろう。これは例えばマルチプレイなどでのPossessのし直しなどで呼び出すことがある。いずれにせよ

- プレイヤ系の初期化もしくはPossess以外のタイミングで、AutoManageActiveCameraTarget()が呼び出されるタイミングはない。
- つまり、何らかの定期処理(Tickなど)でカメラの状態を監視しているわけではない。

ということである。逆にいえば、

- Player ControllerのbAutoManageActiveCameraTargetをtrueにしておけば、ええ感じに臨機応変にCamera ActorがView Targetになってくれるわけではない

ことが注意点になる。

:::note info
要するに「Auto Manage (自動管理)」という言葉のイメージとは違う挙動をするので勘違い注意、と言うことである。
:::

# まとめ

- Player ControllerのAuto Manage Active Camera Targetは、思ったほど自動管理(Auto-Manage)をしてくれるわけではない。
    - プレイヤが初期化あるいは切り替わる(Possess)タイミングでしか呼び出されない。
    - 特に、ゲームの初期化時はTrue/Falseのどちらに設定しても、動作に違いはない。
- Camera ActorのAuto Activate For Playerは、Begin Playでのみ動作する。
    - プレイ中(Tick時など)に自在に切り替える目的では使えない。

# その他

- Player ControllerのAuto Manage Active Camera TargetはデフォルトでTrueになっている。個人的には気持ち悪いのでマメにFalseにして、自分で明示的にView Targetを設定したい。
    - ちなみに、Auto Manage Active Camera TargetをTrueにすると、APlayerCameraManager::SetViewTarget()の呼び出し回数は10回くらいある。実際のところは大した負荷にはならないだろうが、これまた気持ちが悪い。
    - ちなみに、Auto Manage Active Camera TargetをFalseにすると、APlayerCameraManager::SetViewTarget()の呼び出し回数は1回である。妙に気が楽になる。
        - ただし、この場合のデフォルトのView TargetはPlayer Controllerになるので、プログラマ側で明示的に望むView Targetを設定しなくてはならない。
- Camera <b>Component</b>にはAuto Activate For Playerの機能はない。あくまでCamera <b>Actor</b>の機能である。
    - Auto Activate For Playerを使ってええ感じに動くカメラを作りたい場合は、素のActorにCamera Componentを付けるのではなく、Camera Actorを継承したアクタを作る必要がある。

:::note info
個人的には、Player ControllerのAuto Manage Active Camera Targetも、Camera ActorのAuto Activate For Playerも、今後使うことはないだろうな、と思っている。
:::