Switching Between Multiple Tanks

Hello, I placed 4 tanks on the map and added some code to switch between them whenever a projectile is fired. I can get the PlayerController to possess a new tank, but for some reason the turret mesh only rotates around for the original tank from Player Start (as seen in the gif below).

tanks

When I try to log out the tank being controlled,

	FString PawnName = UGameplayStatics::GetPlayerController(this, 0)->GetPawn()->GetActorNameOrLabel();
	UE_LOG(LogTemp, Display, TEXT("[Testing] Turrent Mesh belongs to: %s %s"), *TurretMesh->GetOwner()->GetActorNameOrLabel(), *PawnName);

LogTemp: Display: [Testing] Turrent Mesh belongs to: BP_PawnTank BP_PawnTank
LogTemp: Display: [Testing] Turrent Mesh belongs to: BP_PawnTank Tank3

The Tank get’s updated for the PlayerController, but the turret mesh always has the original player start tank as the owner.

I added a Timer inside AProjectile::onHit and calls ChangePlayer inside AToonTanksPlayerController.

The Towers all rotate independently. Is there something I am missing in order to rotate the turret mesh individually for each tank?

How do you rotate the tank’s turret?

It’s the same way as the lecture inside the Tick function of Tank.cpp.

void ATank::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	if (TankPlayerController)
	{
		FHitResult HitResult;
		TankPlayerController->GetHitResultUnderCursor(ECollisionChannel::ECC_Visibility, false, HitResult);
		//DrawDebugSphere(GetWorld(), HitResult.ImpactPoint, 10, 10, FColor::Red, false, -1);
		RotateTurret(HitResult.ImpactPoint);
		UE_LOG(LogTemp, Display, TEXT("[TESTING] PLAYER CONTROLLER PAWN: %s"), *TankPlayerController->GetPawn()->GetActorNameOrLabel())
	}
}

And then the RotateTurret inside BasePawn.cpp

void ABasePawn::RotateTurret(FVector LookAtTarget)
{
	UE_LOG(LogTemp, Warning, TEXT("IS CHILD OF: %d"), UGameplayStatics::GetPlayerController(this, 0)->GetPawn()->GetClass()->IsChildOf(ATank::StaticClass()));
	FVector ToTarget = LookAtTarget - TurretMesh->GetComponentLocation();
	FRotator LookAtRotation = FRotator(0.f, ToTarget.Rotation().Yaw, 0.f);
	FString PawnName = UGameplayStatics::GetPlayerController(this, 0)->GetPawn()->GetActorNameOrLabel();
	UE_LOG(LogTemp, Display, TEXT("[Testing] Turrent Mesh belongs to: %s %s"), *TurretMesh->GetOwner()->GetActorNameOrLabel(), *PawnName);
	TurretMesh->SetWorldRotation(FMath::RInterpTo(TurretMesh->GetComponentRotation(), LookAtRotation, UGameplayStatics::GetWorldDeltaSeconds(this), 5.f));
}

Sorry, that was intended to be a hint to the issue. To be a little more speciific

if (TankPlayerController)

What is the value of TankPlayerController for all tanks. Does it change when you swap tanks?

Yes the value for TankPlayerController does change when I swap tanks. I thought it wouldn’t be doing that.

If I use UGameplayStatics::GetPlayerController(this, 0)->GetHit… inside the Tick function instead of TankPlayerController->GetHit…, then it rotates every tank simultaneously but I guess that makes sense because it’s being called for each instance of the Tank Class.

void ATank::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

		FHitResult HitResult;
		UGameplayStatics::GetPlayerController(this, 0)->GetHitResultUnderCursor(ECollisionChannel::ECC_WorldStatic, false, HitResult);
		DrawDebugSphere(GetWorld(), HitResult.ImpactPoint, 10, 10, FColor::Red, false, -1);
		RotateTurret(HitResult.ImpactPoint);
		if (TankPlayerController)
	{
		UE_LOG(LogTemp, Display, TEXT("[PLAYERCONTROLLER] PLAYER CONTROLLER PAWN: %s"), *TankPlayerController->GetPawn()->GetActorNameOrLabel())
	}
}

But I found a solution by binding the mouse movement to the Tank Class and then calling RotateTurretAlt from the BasePawn class.

PlayerInputComponent->BindAxis(TEXT("RotateTurret"), this, &ATank::RotateTurretAlt);
void ATank::RotateTurretAlt(float Value)
{
	RotateTankTurret(Value);
}

And then in BasePawn.cpp

void ABasePawn::RotateTankTurret(float Value)
{
	FHitResult HitResult;
	UGameplayStatics::GetPlayerController(this, 0)->GetHitResultUnderCursor(ECollisionChannel::ECC_WorldStatic, false, HitResult);
	DrawDebugSphere(GetWorld(), HitResult.ImpactPoint, 10, 10, FColor::Red, false, -1);
	FVector ToTarget = HitResult.ImpactPoint - TurretMesh->GetComponentLocation();
	FRotator LookAtRotation = FRotator(0.f, ToTarget.Rotation().Yaw, 0.f);
	FString PawnName = UGameplayStatics::GetPlayerController(this, 0)->GetPawn()->GetActorNameOrLabel();
	UE_LOG(LogTemp, Display, TEXT("[BasePawn RotateTankTurret] Turrent Mesh belongs to: %s %s and movement is: %s"), *TurretMesh->GetOwner()->GetActorNameOrLabel(), *PawnName, *LookAtRotation.ToString());
	TurretMesh->SetWorldRotation(FMath::RInterpTo(TurretMesh->GetComponentRotation(), LookAtRotation, UGameplayStatics::GetWorldDeltaSeconds(this), 5.f));

}

Is this a good way to do it or is there a better solution?

Instead of storing it from BeginPlay you can just call GetController and cast in tick. As the tank is only controlled by a playercontroller you can use CastChecked which does the checking for you and is turned into a static cast in shipping builds.

Alternatively swap it when you change player, or alternatively again, override PossessedBy() and UnPossessed()