How do I temporarily set a Controller as a Spectator Pawn?

I’m looking at setting a controller as a spectator pawn in an online game like so…

for (FConstPlayerControllerIterator It = GetWorld()->GetPlayerControllerIterator(); It; ++It)
{
      AOnlineController* TestPC = Cast<AOnlineController>(*It);
      ASpectatorPawn* TestSpec = Cast<ASpectatorPawn>(*It);
      if (TestPC && TestPC->IsLocalController())
      {
           TestPC->SetSpectatorPawn(TestSpec);
	       TestPC->BeginSpectatingState();
      }
}

This is pretty much guess work on finding little pieces of information in the documentation and I am relatively new to Unreal, now after setting this up when in game I press ‘L’ which triggers the above code however I can then no longer move.

So I was wondering if this is the best way to go about setting the pawn as a spectator or am I just missing something? I’ve read in the documentation that the default movement of ASpectatorPawn is the zero gravity sort of flying round the scene movement and thought when setting the controllers spectator pawn this would occur by default?

From the looks of it, you’re trying to cast a PlayerController to a Pawn.
That won’t work.

The pawn used for spectating shouuld be created automatically when the player controller enters the spectating state.
Try this:

    for(FConstPlayerControllerIterator It = GetWorld()->GetPlayerControllerIterator(); It; ++It)
    {
	    AOnlineController* TestPC = Cast<AOnlineController>(*It);
        if (TestPC && TestPC->IsLocalController())
        {
            TestPC->PlayerState->bIsSpectator = true;
            TestPC->ChangeState(NAME_Spectating);
        }
    }

It should set the player to a non-permanent spectator.

Cheers works great now!

In terms of setting the player back to a playing state I tried

for(FConstPlayerControllerIterator It = GetWorld()->GetPlayerControllerIterator(); It; ++It)
    {
        AOnlineController* TestPC = Cast<AOnlineController>(*It);
        if (TestPC && TestPC->IsLocalController())
        {
            TestPC->PlayerState->bIsSpectator = false;
            TestPC->ChangeState(NAME_Playing);
        }
    }

Which just gets me stuck with the same problem as before the controller will no longer move, I’m guessing I may have to repossess the original pawn I was using before setting the state to spectating?

Yep :slight_smile:

TestPC->SetPawn(OriginalPawn);
TestPC->ChangeState(NAME_Playing);

No need to do TestPC->PlayerState->bIsSpectator = false; - changing state will do that.

I ended up using

TestPC->Possess(OriginalPawn);
TestPC->ChangeState(NAME_Playing);

SetPawn() seemed to attach the controller to the pawn but all controls still appeared to be disabled however using Possess() seems to work fine and I can now switch from a spectating and playing state at the press of a key, thanks for the help!

In case of multi player, we found that the ChangeState method and StateName variable are not automatically replicated. So you need to call ClientGotoState method on the server. The spectate code become:

TestPC->PlayerState->bIsSpectator = true;
TestPC->ChangeState(NAME_Spectating);
TestPC->ClientGotoState(NAME_Spectating);

and

TestPC->PlayerState->bIsSpectator = false;
TestPC->Possess(OriginalPawn);
TestPC->ChangeState(NAME_Playing);
TestPC->ClientGotoState(NAME_Playing);
1 Like