I’m currently making a card game that has 4 players. If there is only 1 client, then there will be 3 AI players. I have that much working already, but what if another player joins the game? How can I tell when a new client joins and how can I correctly place the new client into the game?
This can be done in the GameMode with the PreLogin and PostLogin functions. I check if the AI is controlled via IsControlled(). If it isn’t then a human player is free to take it. AIControllers are spawned automatically, so it seems like IsControlled() should always return true, but it appears to work regardless. I suppose if you want to be double sure, you can make your own AIController and PlayerController and test which one is controlling the pawn. Here is my current setup:
void AMyGameMode::PreLogin(const FString & Options, const FString & Address, const TSharedPtr<class FUniqueNetId>& UniqueId, FString& ErrorMessage)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Client connected"));
if (IsPawnAvailable())
{
Super::PreLogin(Options, Address, UniqueId, ErrorMessage);
}
else
{
//setting the error message will disconnect the player
ErrorMessage = TEXT("Game is full. Please try another.");
}
}
void AMyGameMode::PostLogin(APlayerController* NewPlayer)
{
Super::PostLogin(NewPlayer);
ASPawn* FreePawn = GetFreePawn();
NewPlayer->Possess(FreePawn);
// probably redundant
FreePawn->SetOwner(NewPlayer);
ConnectedClients++;
// at least 1 connected client before the game starts
if (ConnectedClients == 1)
{
PreGameSetup();
}
}
ASPawn* AMyGameMode::GetFreePawn()
{
for (TActorIterator<AAIPlayer> ActorItr(GetWorld()); ActorItr; ++ActorItr)
{
if (!ActorItr->IsControlled())
{
return *ActorItr;
}
}
return NULL;
}
bool AMyGameMode::IsPawnAvailable()
{
for (TActorIterator<AAIPlayer> ActorItr(GetWorld()); ActorItr; ++ActorItr)
{
if (!ActorItr->IsControlled())
{
return true;
}
}
return false;
}
Possessing pawns:
More ways to connect players: