text: // Copyright (c) JLSA:
  
  #include "TankPlayerController.h"
  #include "TankAimingComponent.h"
  #include "Runtime/Engine/Classes/Engine/World.h"
  #include "Tank.h"
  
  
  void ATankPlayerController::OnPossedTankDeath()
  {
  	StartSpectatingOnly();
  }
  
  void ATankPlayerController::BeginPlay()
  {
  	Super::BeginPlay();
  	if (!GetPawn()) return;
  	auto AimingComponent = GetPawn()->FindComponentByClass<UTankAimingComponent>();
  	if (!ensure(AimingComponent)) return;
  	FoundAimingComponent(AimingComponent);
  }
  
  void ATankPlayerController::Tick(float DeltaTime)
  {
  	Super::Tick(DeltaTime);
  	AimTowardsCrosshair();
  }
  
  void ATankPlayerController::SetPawn(APawn * InPawn)
  {
  	Super::SetPawn(InPawn);
  	if (InPawn)
  	{
  		auto PossessedTank = Cast<ATank>(InPawn);
  		if (!ensure(PossessedTank)) { return; }
  
  		// Subscribe our local method to the tank's death event
  		PossessedTank->OnDeath.AddUniqueDynamic(this, &ATankPlayerController::OnPossedTankDeath);
  	}
  }
  
  void ATankPlayerController::AimTowardsCrosshair()
  {
  	if (!ensure(GetPawn())) return; // e.g. if it is not possessing
  	auto AimingComponent = GetPawn()->FindComponentByClass<UTankAimingComponent>();
  	if (!ensure(AimingComponent)) return;
  
  	FVector HitLocation; // Out parameter
  	bool bGotHitLocation = GetSightRayHitLocation(HitLocation);
  	if (bGotHitLocation) // Has "side-effect", is going to line trace
  	{
  		// Tell controlled tank to aim at this point
  		AimingComponent->AimAt(HitLocation);
  	}
  }
  
  // Get world location of linetrace through crosshair, true if hits landscape
  bool ATankPlayerController::GetSightRayHitLocation(FVector& HitLocation) const
  {
  	// Find the crosshair position in pixel coordinates
  	int32 ViewportSizeX, ViewportSizeY;
  	GetViewportSize(ViewportSizeX, ViewportSizeY);
  	auto ScreenLocation = FVector2D(ViewportSizeX*CrosshairXLocation, ViewportSizeY * CrosshairYLocation);
  
  	// "De-project" the screen position of the crosshair to a world direction
  	FVector LookDirection;
  	if (GetLookDirection(ScreenLocation, LookDirection))
  	{
  		// UE_LOG(LogTemp, Warning, TEXT("Look direction: %s"), *LookDirection.ToString());
  		// Line-trace along that look direction, and see what we hit (up to max range)
  		return GetLookVectorHitLocation(LookDirection, HitLocation);
  	}
  
  	return false;
  }
  
  bool ATankPlayerController::GetLookDirection(FVector2D ScreenLocation, FVector& LookDirection) const
  {
  	FVector CameraWorldLocation; // To be discared
  	return DeprojectScreenPositionToWorld(
  		ScreenLocation.X,
  		ScreenLocation.Y,
  		CameraWorldLocation,
  		LookDirection
  	);
  }
  
  bool ATankPlayerController::GetLookVectorHitLocation(FVector LookDirection, FVector& HitLocation) const
  {
  	FHitResult HitResult;
  	auto StartLocation = PlayerCameraManager->GetCameraLocation();
  	auto EndLocation = StartLocation + (LookDirection*LineTraceRange);
  	if (GetWorld()->LineTraceSingleByChannel(HitResult, StartLocation, EndLocation, ECollisionChannel::ECC_Camera))
  	{
  		// Set hit location
  		HitLocation = HitResult.Location;
  		return true;
  	}
  	HitLocation = FVector(0);
  	return false; // Line trace didn't succeed
  }
  