How can I create custom spawn logic in a networked game?

Hello everyone!

I’m currently trying to create a networked game where several players are supposed to play against each others. This have been working rather well without any real spawn logic so far, but now I need it to be able to test the needed functionalities.

My biggest issue here is to find resources about this matter, I might just be blind, but i haven’t found anything regarding custom spawning. I’d be vary grateful if someone could send a link or just give a short example of how to implement custom logic so i could get started with creating my own!

Regards

FreeSirenety

Players will spawn at the usual playerstart actors, but you can entirely specify spawning logic via these Game Mode functions (some are not part of GameMode but are used by the others):

I took this code from the ShooterGame example and have used it in my own game in real multiplayer matches :slight_smile: (thanks Epic!)

/** select best spawn point for player */
virtual AActor* ChoosePlayerStart(AController* Player) OVERRIDE;

/** check if player can use spawnpoint */
virtual bool IsSpawnpointAllowed(APlayerStart* SpawnPoint, AController* Player) const;

/** check if player should use spawnpoint */
virtual bool IsSpawnpointPreferred(APlayerStart* SpawnPoint, AController* Player) const;

/** Choosing Start Point */
AActor* AVictoryGameGameMode::ChoosePlayerStart(AController* Player)
{
	static TArray<APlayerStart*> PreferredSpawns;
	static TArray<APlayerStart*> FallbackSpawns;
	PreferredSpawns.Reset();
	FallbackSpawns.Reset();

	for (int32 i = 0; i < PlayerStarts.Num(); i++)
	{
		APlayerStart* TestSpawn = PlayerStarts[i];
		if (IsSpawnpointAllowed(TestSpawn, Player))
		{
			if (IsSpawnpointPreferred(TestSpawn, Player))
			{
				PreferredSpawns.Add(TestSpawn);
			}
			else
			{
				FallbackSpawns.Add(TestSpawn);
			}
		}
	}

	APlayerStart* BestStart = NULL;
	if (PreferredSpawns.Num() > 0)
	{
		BestStart = PreferredSpawns[FMath::RandHelper(PreferredSpawns.Num())];
	}
	else if (FallbackSpawns.Num() > 0)
	{
		BestStart = FallbackSpawns[FMath::RandHelper(FallbackSpawns.Num())];
	}

	return BestStart ? BestStart : Super::ChoosePlayerStart(Player);
}
bool AVictoryGameGameMode::IsSpawnpointAllowed(APlayerStart* SpawnPoint, AController* Player) const
{
	return true;
}

bool AVictoryGameGameMode::IsSpawnpointPreferred(APlayerStart* SpawnPoint, AController* Player) const
{
	ACharacter* MyPawn = Player ? Cast<ACharacter>(Player->GetPawn()) : NULL;
	if (MyPawn)
	{
		const FVector MyLocation = MyPawn->GetActorLocation();
		for (FConstPawnIterator It = GetWorld()->GetPawnIterator(); It; ++It)
		{
			ACharacter* OtherPawn = Cast<ACharacter>(*It);
			if (OtherPawn && OtherPawn != MyPawn)
			{
				const float CombinedHeight = (MyPawn->CapsuleComponent->GetScaledCapsuleHalfHeight() + OtherPawn->CapsuleComponent->GetScaledCapsuleHalfHeight()) * 2.0f;
				const float CombinedRadius = MyPawn->CapsuleComponent->GetScaledCapsuleRadius() + OtherPawn->CapsuleComponent->GetScaledCapsuleRadius();
				const FVector OtherLocation = OtherPawn->GetActorLocation();

				// check if player start overlaps this pawn
				if (FMath::Abs(MyLocation.Z - OtherLocation.Z) < CombinedHeight && (MyLocation - OtherLocation).Size2D() < CombinedRadius)
				{
					return false;
				}
				
				//Check if there's any player within 512
				if(SpawnPoint)
				{
				if ((SpawnPoint->GetActorLocation() - OtherLocation).SizeSquared() < 262144) 
				{
					return false;
				}
				}
			}
		}
	}

	return true;
}

Rama, have you confirmed that all of the code you have within the if(MyPawn) null check is being executed? i have a similar setup for my spawning and the AController* Player passed to ChoosePlayerStart(AController* Player) is always null.

hey bud, if you’re still looking for some information on custom spawning, i wrote out what i did for spawning at different player starts based on the PlayerStartTag. it ain’t too pretty, but its simple and a good start. the problem i was having with what Rama was doing is that the controller being passed to those functions is NULL at least the first time through, so i couldn’t actually get the functions to retrieve the player team information i had stored in the PlayerState.

check this:

hope it helps!