Download

Banging my head trying to figure out how to smoothly rotate actor to cursor

Hey guys I’m in a tight bind over here, I am trying to get a smooth rotation of an ACharacter to the mouse cursor, and so far I’ve come up with this:

	// Perform a trace and get the mouse hit position vector.
	PlayerControllerRef->GetHitResultUnderCursor(TraceChannel, Complex, Hit);
	MouseHitPos = Hit.ImpactPoint;
	// [DEBUGGING] -- Uncomment this to see trace to cursor
	// UKismetSystemLibrary::DrawDebugLine(GetWorld(), GetActorLocation(), MouseHitPos, FColor::Red, 1.f, 5.f);

	// Get a vector from  the mouse hit point to the actor location
	FVector ActorLocationToHitPoint = (MouseHitPos - GetActorLocation());

	if (ActorLocationToHitPoint.Size() > 150.f)
	{
		FRotator UpdateTurningRotation = FMath::RInterpConstantTo(GetActorRotation(), MouseHitPos.Rotation(), DeltaTime, 300.f);
		//Orient pawn to the cursor.
		SetActorRotation(FRotator(0.f,UKismetMathLibrary::FindLookAtRotation(GetActorLocation(), UpdateTurningRotation.Vector()).Yaw,0.f));
	}

	// [DEBUGGING] -- Uncomment this to see position of cursor
	// UE_LOG(LogTemp, Warning, TEXT("MouseHitPos: %s ActorLocationToHitPoint: %s ActorLocationToHitPoint.Size : %f"), *MouseHitPos.ToString(), *ActorLocationToHitPoint.ToString(), ActorLocationToHitPoint.Size());

The problem is I got the behavior I want, which is a smooth transition from the actor to the direction of the cursor, however I’m unable to move it seems like the calculations at each tick is making my character unable to process movement inputs.

I want to be able to:

Get a trace from the actor to the cursor->RInterp to the rotation of where the the cursor is located.

Currently if I just remove the RInterp, set Actor location snaps the actor towards the actor, and I don’t know if I can get away from that.

Is this just a limited due to the engine’s capability?

Update, I found out that the only good workaround to this is to simply use a 2D blendspace to handle how to character behaves in a top-down scenario, it’s no good relying on code to smooth out the turning because what is happening with the code above is that it will always be interpolating again before the next tick occurs. So what happens is tick->Interpolate->Interpolate doesn’t finish but new tick comes->Interpolate happens, and it keeps stacking up.

Just use a Blendspace.

You don’t need to do a lerp at all. Just turn by x degrees each second until you reach your destination.

float AmountLeftToTurn = FMath::Acos(FVector::Dot(ActorLocationToHitPoint.Normalize(), GetActorForward)); // Get the angle between the Player and where we want to turn to, in radians.

float TurnSpeedInDegreesPerSecond = 90.0f; // Make this a property or something. 
float RadiansToTurn = FMath::DegreesToRadians(TurnSpeedInDegreesPerSecond) * DeltaTime; // Convert to Radians Per Second and scale by time.

RadiansToTurn = FMath::Min(RadiansToTurn, AmountLeftToTurn); // Take whichever value is lower so we don't swing past our Target.

// Apply the Rotation using SetActorLocation and a Quat / Rotator.

EDIT: Function names may be incorrect. It’s late and I don’t want to open Visual Studio again. :slight_smile:

You might also be better off controlling the ControlRotation of the Controller as opposed to moving the actor if it gets in the way of other things.

1 Like

That’s actually really clever, I’ll try it out.