Cancel set view target with blend and blend backward

Hi all, I’m currently working on a point of interest mechanic which blends the players camera to a cine camera to view some point of interest when they hold down an interaction key, and then blends back when they release the key. I though I could get away with a simple SetViewTargetWithBlend(CineCameraActor, …) when they start holding down the interact key, and then do another SetViewTargetWithBlend(PlayerCharacter, …) when they release it - which works fine if they hold it long enough for the blend to reach the cinecamera before releasing. But, if they release the interact key before the blend completes, then instead of smoothly blending back to the player character, it just immediately snaps back to the player character.

So the question becomes, is there a way to smoothly blend back to the player character if they release the key before it completes its current blend using SetViewTargetWithBlend? The alternative I’m thinking of is just to do a manual lerp to the cinecamera’s position and then set view target…

Hi there,
I have never tried this before, but I am quite sure you cannot interrupt a latent function that operates with a delay. Also, we don’t have access to the actual camera position in world space in real time, directly exposed in the set view target w/ blend, unless you access this variable via C++ or custom Blueprint code using tick event with get world location. Maybe it’s worth a try.

You may want to try the node “Move Component to”, which also has location and rotation and lerps between two positions with custom curves and a delay time. It’s also worth trying.

You can for sure prevent the code being triggering halfway through by using a Boolean at the end of the 1st set view target w/ blend. If player releases the input, a branch will check “if the blend was finished” before attempting to reverse it and loop through a “delay until next tick”.

I’ll see if I can find anything useful and share here.

2 Likes

Checked this out - had a go at it in C++ but was having some weird behaviour with the camera moving to the given location / rotation, I eventually resorted to just writing up my own interp functionality, where firstly on the POI actor I have a BeginFocus method triggered when the player interacts with the POI actor:

void APinchPoint::BeginFocus()
{
	bTransitionBackActive = false;
	bTransitionForwardActive = true;
	SetActorTickEnabled(true);
}

Then in the tick function, it has this block which will interp the camera to the UCineCamera’s position before performing the set view target

if (bTransitionForwardActive)
	{
		if (PlayerCamera->GetComponentLocation().Equals(CineCamera->GetComponentLocation(), 1.f))
		{
			UGameplayStatics::GetPlayerController(GetWorld(), 0)->SetViewTargetWithBlend(this, 0.1f);
			bTransitionForwardActive = false;
			SetActorTickEnabled(false);
		}
		else
		{
			PlayerCamera->SetWorldLocation(FMath::VInterpTo(PlayerCamera->GetComponentLocation(), CineCamera->GetComponentLocation(), DeltaTime, 1.f));
			PlayerCamera->SetWorldRotation(FMath::RInterpTo(PlayerCamera->GetComponentRotation(), CineCamera->GetComponentRotation(), DeltaTime, 1.f));
		}
	}

And then when the player releases the interact button, it calls the EndFocus method on the POI actor:

void APinchPoint::EndFocus()
{
	if (UGameplayStatics::GetPlayerCameraManager(GetWorld(), 0)->ViewTarget.Target == this)
	{
		UGameplayStatics::GetPlayerController(GetWorld(), 0)->SetViewTargetWithBlend(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));	
	}
	bTransitionForwardActive = false;
	bTransitionBackActive = true;
	SetActorTickEnabled(true);
}

Which will enable the following block in tick to enable moving the camera back:

else if (bTransitionBackActive)
	{
		if (PlayerCamera->GetComponentLocation().Equals(OriginalCameraLocation, 1.f))
		{
			bTransitionBackActive = false;
			SetActorTickEnabled(false);
		}
		else
		{
			PlayerCamera->SetRelativeLocation(FMath::VInterpTo(PlayerCamera->GetRelativeLocation(), FVector::ZeroVector, DeltaTime, 1.f));
			PlayerCamera->SetRelativeRotation(FMath::RInterpTo(PlayerCamera->GetRelativeRotation(), FRotator::ZeroRotator, DeltaTime, 1.f));
		}
	}

It’s a bit rough at the moment but it gets the job done! I might look at the MoveComponentTo a bit more further in the future though…

2 Likes

This looks fantastic. It is worth improving it.
Well done.