Download

Trouble with Aiming a Tank Turret to Mouse Position in 3rd Person, with an orbital camera.

Solved: See 2nd reply (3rd post)


    
    FVector2D AimLocation;
    if (UGameplayStatics::GetPlayerController(GetWorld(), 0)->GetMousePosition(AimLocation.X, AimLocation.Y))
    {
        FVector2D TurretLocation = FVector2D::ZeroVector;
        UGameplayStatics::ProjectWorldToScreen(UGameplayStatics::GetPlayerController(GetWorld(), 0), MainBody->GetComponentLocation(), TurretLocation);
        float DesiredYaw;
        //AimLocation = AimLocation.GetSafeNormal(0.01f);        
        if (UStaticsBDSM::FindLookAtAngle2D(TurretLocation, AimLocation, DesiredYaw))
        {
            DesiredYaw += 90;
            FRotator CurrentRotation = ChildTurret->GetComponentRotation();
            float DeltaYaw = UStaticsBDSM::FindDeltaAngleDegrees(CurrentRotation.Yaw, DesiredYaw);
            float RemainingRotation = FMath::Abs(DesiredYaw - CurrentRotation.Yaw);
            float MaxDeltaYawThisFrame = YawSpeed * DeltaTime;
            if (FMath::Abs(DeltaYaw) > MaxDeltaYawThisFrame)
            {
                if (RemainingRotation > 0.0f)
                {
                    ChildTurret->AddRelativeRotation(FRotator(0.0f, FMath::Sign(DeltaYaw) * MaxDeltaYawThisFrame, 0.0f));
                }
                else
                {
                    return;
                }
            }
        }
    }
    }

Im using the mouse aiming logic in the Tanks vs Zombies tutorials, and it works great for top down orthographic, but my project is 3rd person with about a 45-60 deg camera angle. The code pretty much works, except when aiming at the corners of the viewport, the aim is offset by a very noticeable amount, but will line up when aim at center top/bottom/right/left. Only the corners are offset. I’ve been googling for hours, but none of the search results are yielding anything that even remotely works. Would really appreciate some help.


    
    FVector MouseLocation, MouseDirection;
    UGameplayStatics::GetPlayerController(GetWorld(), 0)->DeprojectMousePositionToWorld(MouseLocation, MouseDirection);
    MouseDirection *= 10000.0f;
    MouseDirection += MouseLocation;
    FHitResult HitOutPut;
    GetWorld()->LineTraceSingleByChannel(HitOutPut, MouseLocation, MouseDirection, ECC_WorldStatic);
    FVector Target = HitOutPut.ImpactPoint;
    FVector Start = ChildTurret->GetComponentLocation();
    FRotator DesiredRotation = UKismetMathLibrary::FindLookAtRotation(Start,Target);
    FRotator RootRotation = MainBody->GetComponentRotation();
    DesiredRotation.Yaw -= RootRotation.Yaw;
    DesiredRotation.Yaw;
    ChildTurret->SetRelativeRotation(FRotator(0.0f, DesiredRotation.Yaw, 0.0f));


I got this to work (on Tick) but obviously the turning is instant. I’ve tried FInterpTo with normal and extreme values on DeltaTime/Interp Speed, and the turret either spins like a top, or is instant. So now if anyone has some input on slowly transitioning from Existing Yaw to Desired Yaw over a time/speed, using “SetRelativeRoation” that would be very helpful. Unfortunately the other rotation commands wont give the desired results.

This was my solution, in case it helps anyone else.



    FVector MouseLocation, MouseDirection;
    if (UGameplayStatics::GetPlayerController(GetWorld(), 0)->DeprojectMousePositionToWorld(MouseLocation, MouseDirection))
    {
        MouseDirection *= 10000.0f;
        MouseDirection += MouseLocation;
        FHitResult HitOutPut;
        if (GetWorld()->LineTraceSingleByChannel(HitOutPut, MouseLocation, MouseDirection, ECC_WorldStatic))
        {
            FVector Target = HitOutPut.ImpactPoint;
            FVector Start = ChildTurret->GetComponentLocation();
            FRotator DesiredRotation = UKismetMathLibrary::FindLookAtRotation(Start, Target);
            FRotator CleanRotation = DesiredRotation;
            FRotator RootRotation = MainBody->GetComponentRotation();
            DesiredRotation.Yaw -= RootRotation.Yaw;
            FRotator StartRot = ChildTurret->GetComponentRotation();            
            AdjustedDesiredRotation = StartRot.Yaw - CleanRotation.Yaw;            
            float AdjustedSign = FMath::Sign(AdjustedDesiredRotation) * -1.0f;            
            if (FMath::Abs(AdjustedDesiredRotation) > 180.0f)            
            {                
                 AdjustedDesiredRotation = (180.0f - (FMath::Abs(AdjustedDesiredRotation) - 180.0f)) * AdjustedSign;            
            }
            float MaxDeltaYawThisFrame = YawSpeed * DeltaTime;
            if (!(FMath::Abs(AdjustedDesiredRotation) > MaxDeltaYawThisFrame))
            {
                ChildTurret->SetRelativeRotation(FRotator(0.0f, DesiredRotation.Yaw, 0.0f));
            }
            else
            {
                ChildTurret->AddRelativeRotation(FRotator(0.0f, ((FMath::Sign(AdjustedDesiredRotation) * MaxDeltaYawThisFrame) * -1.0f), 0.0f));
            }
        }
    }