[Request] USpringArmComp::BlendLocations Not Const Please, Makes VInterpTo hard to use

#My Entire Beautifully Working Follow Cam
Please see last comment for entire code of my beautifully working, smoothly blending follow camera, and in the code you will see my reason for this thread


Dear Friends at Epic,

First off, thank you for making the BlendLocation function!

And THANK YOU for making this and updatedesiredlocation virtual!

Yaaay!

Thanks!

But please, could you consider making the BlendLocations function not Const ?

It means I cannot store a variable for blending the location using VInterpTo within the springarm class itself


#Simple Blend, VInterpTo

Given all the parameters passed to BlendLocation a simple and lovely function to use is VInterpTo

but for lack of ability to store a global variable within the class itself it is impossible to use as far as I know


#I have Achieved Smooth Camera Movement, but Had to rely on external variable

In order to use VInterpTo to create a smoothly moving camera, I had to actually store a variable in my player controller class, and give the spring arm component access to my player controller

I should not have to do this

but since the function is const I had to :slight_smile:

Here’s what I did, to achieve my desire result of smoothly transitioning camera:


#VictoryPC->CameraSpringArmProgress

In the code below the use of the variable from external class is my only real point in this thread, I dont know a way around this given the const restriction on the function

// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "VictorySpringArmComp.generated.h"

/**
 * This component tried to maintain its children at a fixed distance from the parent,
 * but will retract the children if there is a collision, and spring back when there is no collision.
 *
 * Example: Use as a 'camera boom' to keep the follow camera for a player from colliding into the world.
 */

UCLASS(dependson=UVictoryCore)
class UVictorySpringArmComp : public USpringArmComponent
{
	GENERATED_UCLASS_BODY()
	
	//Should Camera Move if View is Blocked?
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=VictorySpringArm)
	bool MoveIfViewBlocked;
	
	//How Fast Camera Should Move When View Is Blocked
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=VictorySpringArm)
	float ViewAdjustSpeed;
	
	//for testing
	AVictoryGamePlayerController* VictoryPC;
	
protected:
	
	
	/** Updates the desired arm location, calling BlendLocations to do the actual blending if a trace is done */
	virtual void UpdateDesiredArmLocation(const FVector& Origin, const FRotator& Direction, bool bDoTrace, float DeltaTime) OVERRIDE;

	/**
	 * This function allows subclasses to blend the trace hit location with the desired arm location;
	 * by default it returns bHitSomething ? TraceHitLocation : DesiredArmLocation
	 */
	virtual FVector BlendLocations(const FVector& DesiredArmLocation, const FVector& TraceHitLocation, bool bHitSomething, float DeltaTime) const OVERRIDE;
};

.cpp

// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.

#include "VictoryGame.h"

//////////////////////////////////////////////////////////////////////////
// UVictorySpringArmComp

UVictorySpringArmComp::UVictorySpringArmComp(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)
{
	MoveIfViewBlocked = true;
	ViewAdjustSpeed = 3;
}

/** Updates the desired arm location, calling BlendLocations to do the actual blending if a trace is done */
void UVictorySpringArmComp::UpdateDesiredArmLocation(const FVector& Origin, const FRotator& Direction, bool bDoTrace, float DeltaTime)
{
	Super::UpdateDesiredArmLocation(Origin, Direction, bDoTrace, DeltaTime);
}


/**
 * This function allows subclasses to blend the trace hit location with the desired arm location;
 * by default it returns bHitSomething ? TraceHitLocation : DesiredArmLocation
 */
FVector UVictorySpringArmComp::BlendLocations(const FVector& DesiredArmLocation, const FVector& TraceHitLocation, bool bHitSomething, float DeltaTime) const
{

if (!VictoryPC) 			return DesiredArmLocation; //Should not need this, but the func is const
if (!MoveIfViewBlocked) 	return DesiredArmLocation;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

if (!bHitSomething)
{
	VictoryPC->CameraSpringArmProgress = DesiredArmLocation;
	return DesiredArmLocation;
}

VictoryPC->Optimize("Something was in way!");

//VInterpTo, could also try VInterpConstantTo with same parameters
VictoryPC->CameraSpringArmProgress = FMath::VInterpTo(VictoryPC->CameraSpringArmProgress, TraceHitLocation, DeltaTime, ViewAdjustSpeed);

return VictoryPC->CameraSpringArmProgress;

}


#I Promise

I promise not to change any other class variables during runtime!

Thanks for considering this!

Rama

#Final Form of My BlendLocations

Below is the final form of my perfectly functioning follow camera which smoothly and beautifully takes into account surround landscapes and static mesh obstacles

it looks awesome

buuut

you see all those references to functions and variables in TheCharacter?

I am just outsourcing the interpolation computations to a difference class because the BlendLocations is const

#if BlendLocations was not const

then I would not need any external class instances references at all!

FVector UVictorySpringArmComp::BlendLocations(const FVector& DesiredArmLocation, const FVector& TraceHitLocation, bool bHitSomething, float DeltaTime) const
{
	if (!VictoryPC) 			return DesiredArmLocation; //Should not need this, but the func is const
	if (!TheCharacter) 
	{
		VictoryPC->Optimize("Cam boom: Character not found!");
		return DesiredArmLocation;
	}
	
	//~~~ Not Current Player Character? ~~~
	if (!TheCharacter->IsCurrentPlayerCharacter) return DesiredArmLocation;
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	//~~~ Move If Blocked? ~~~
	if (!MoveIfViewBlocked) 
	{
		TheCharacter->CamProgAndDesiredMatchedOnce = true;
		TheCharacter->CameraSpringArmProgress = DesiredArmLocation;
		return DesiredArmLocation;
	}
	
	//~~~ No Block ~~~
	if (!bHitSomething)
	{
		if (TheCharacter->CamProgAndDesiredMatchedOnce) 
		{
			//keep CameraSpringArmProgress updated
			TheCharacter->CameraSpringArmProgress = DesiredArmLocation;
			return DesiredArmLocation;
		}
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		
		//Are CamProg and desired sufficiently close again?
		if (FVector::DistSquared(TheCharacter->CameraSpringArmProgress, DesiredArmLocation ) < 6.333) 
		{
			TheCharacter->CamProgAndDesiredMatchedOnce = true;
			return DesiredArmLocation;
			//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		}
		
		//VictoryPC->OptFloat("dist squared", FVector::DistSquared(TheCharacter->CameraSpringArmProgress, DesiredArmLocation ) );
		
		//interp the camera speed incrase back to instant
		TheCharacter->CameraAdjustSpeedProgress = FMath::FInterpTo(TheCharacter->CameraAdjustSpeedProgress,TheCharacter->CameraAdjustSpeedProgress * TheCharacter->CameraAdjustSpeedProgress,DeltaTime, 1); //only cause func is const
		
		//interp the location
		TheCharacter->CameraSpringArmProgress = FMath::VInterpTo(TheCharacter->CameraSpringArmProgress, DesiredArmLocation, DeltaTime, TheCharacter->CameraAdjustSpeedProgress);
		
		return TheCharacter->CameraSpringArmProgress;
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	}
	
	//~~~ Block is Occurring ~~~
	
	//VictoryPC->Optimize("Something was in way!");
	
	if(TheCharacter->CamProgAndDesiredMatchedOnce)
	{
		TheCharacter->CamProgAndDesiredMatchedOnce = false;
		TheCharacter->CameraAdjustSpeedProgress = CAMBLOCK_ADJUSTSPEED;
	}
	
	//Interp the Speed to keep up with fast movnig char while blocked
	TheCharacter->CameraAdjustSpeedProgress = FMath::FInterpTo(TheCharacter->CameraAdjustSpeedProgress, CAMBLOCK_ADJUSTSPEED_MAX, DeltaTime, 3);
	
	//VInterpTo
	TheCharacter->CameraSpringArmProgress = FMath::VInterpTo(TheCharacter->CameraSpringArmProgress, TraceHitLocation, DeltaTime, TheCharacter->CameraAdjustSpeedProgress);
	return TheCharacter->CameraSpringArmProgress;
	
}

Hi Rama,

I went ahead and removed the const from BlendLocations, as it is only called from UpdateDesiredArmLocation anyways. I had just made it const since the theory was that it was just blending between two locations and didn’t need any state. This should be in a future build.

BTW. There’s a sort of ‘const escape’ built into the C++ language called mutable. A mutable member variable can be modified in a const method; it should be used sparingly to avoid unexpected side effects, but it is typically fine for things like side-effect-free caching or reference counts, etc…

Cheers,
Michael Noland

Dear Michael,

Thank you very much for considering this, and for the c++ mutable tip!

And thanks again for making this function and making it virtual!

SpringArmComponent has reached the point where I have been able to implement the third person cam I wanted, to the finest details, and you saved me a looot of work

Thanks again!

#:heart:

Rama