Using Cast<>() in tick

Hello guys I hope that you are doing fine.
Currently I am trying to learn Unreal C++ FPS programming. I guess the best source for learning how to program properly is the examples that the developers provide so I installed unreal 4.27 and loaded up the first person shooter example (not the package content, [This one]) and I saw something rather bizarre in the code (ShooterCharacter.c++):

void AShooterCharacter::OnCameraUpdate(const FVector& CameraLocation, const FRotator& CameraRotation)
{
	USkeletalMeshComponent* DefMesh1P = Cast<USkeletalMeshComponent>(GetClass()->GetDefaultSubobjectByName(TEXT("PawnMesh1P")));
	const FMatrix DefMeshLS = FRotationTranslationMatrix(DefMesh1P->GetRelativeRotation(), DefMesh1P->GetRelativeLocation());
	const FMatrix LocalToWorld = ActorToWorld().ToMatrixWithScale();

	// Mesh rotating code expect uniform scale in LocalToWorld matrix

	const FRotator RotCameraPitch(CameraRotation.Pitch, 0.0f, 0.0f);
	const FRotator RotCameraYaw(0.0f, CameraRotation.Yaw, 0.0f);

	const FMatrix LeveledCameraLS = FRotationTranslationMatrix(RotCameraYaw, CameraLocation) * LocalToWorld.Inverse();
	const FMatrix PitchedCameraLS = FRotationMatrix(RotCameraPitch) * LeveledCameraLS;
	const FMatrix MeshRelativeToCamera = DefMeshLS * LeveledCameraLS.Inverse();
	const FMatrix PitchedMesh = MeshRelativeToCamera * PitchedCameraLS;

	Mesh1P->SetRelativeLocationAndRotation(PitchedMesh.GetOrigin(), PitchedMesh.Rotator());
}

This code runs in the Event Tick and from what I know using a Cast node in the tick event is expensive and should be avoided. On the other hand it’s the developers code so . . . what’s up with that? :sweat_smile: Am I missing something here?

(https://www.unrealengine.com/marketplace/en-US/product/shooter-game))

iirc cpp’s cast isn’t that expensive as bp ones. And even then it’s not such a big deal after the first cast per class per bp.

Anyway:

  1. there are plenty of problems that cannot be solved without casting
  2. it does have some costs, it worth keep that in mind, you shouldn’t stress too much over it or you’ll fall for premature optimization that will eat plenty of time for nothing. So make your code works first and maybe define some profiling stats to keep track of code that may cause performance issues in future.

disclaimer: that’s my personal opinion that may be wrong. So i’m interested in other answers as well. As the saying goes: if you want the corrent answer on the internet - make incorrect statement first /jk

3 Likes

I agree with this.

I see quite a lot of people tying themselves in knots trying not to cast, or even use Tick. They end up making a total mess because they don’t yet understand the subtleties of the engine processes.

Being aware that just plonking anything on Tick can be a bad thing is good. But believing everything you hear on utube will not help…

1 Like

Move DefMesh1P to the header file

UPROPERTY()
	class USkeletalMeshComponent* DefMesh1P;

then during begin play call

DefMesh1P = Cast<USkeletalMeshComponent>(GetClass()->GetDefaultSubobjectByName(TEXT("PawnMesh1P")));
	

in the tick you can do a nullptr check

if(DefMesh1P!=nullptr){
// rest of code with DefMesh1P
}

You will just pay the upfront cost of the cast and then it should be fine. No casting needed during tick as you should have the correct pointer set.

During contruction (CDO) you might want to call

DefMesh1P = CreateDefaultSubObject<USkeletalMeshComponent>(TEXT("DefMesh1P"));
3 Likes

It should be avoided to make a default object into a member of a non default object hence why it probably wasn’t made into a member variable in the first place.

Keep it simple and just use the Cast and don’t worry at all about the tiny overhead.

1 Like

But in the current state of the casting, not only are you constantly casting per frame but also allocating memory for DefMesh1P as it is a local variable that perishes once OnCameraUpdate ends. This is wasteful.

This type of lazy programming will stack up with time and slow the project to a crawl.

You can use local variables for things that are once off fire and forget events but it shouldn’t be done in the case of tick functions.

It’s a matter of scope and memory management. Sure it’s on the stack but it’s still constant shuffling of data that is not needed.

The CDO init may not be needed but if the cast fails then you’ll be left with an empty pointer and cause a crash. So either init it or check it.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.