UpdateChildTransforms() needed when standing still, not when moving

Not sure if this is a bug but it seems rather unintuitive at the very least. When adding a scene component structure, like the one below, on an object (have tried Character and custom physics based character-like actor) the positions does not update on screen (e.g. doing head bobbing or weapon recoil in code) unless the Capsule Component (root) is moving or rotating. In the details tab the transforms are updating, but the visuals are not updated until moving or rotating again

PlayerBody = CreateDefaultSubobject(TEXT("PlayerBody")); PlayerBody->AttachParent = GetCapsuleComponent(); PlayerBody->RelativeLocation = FVector(0.0f, 0.0f, 0.0f);

 CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComponent"));
 CameraComponent->AttachParent = PlayerBody;
 CameraComponent->RelativeLocation = FVector(0.0f, 0.0f, 75.0f);
 CameraComponent->bUsePawnControlRotation = false;
 
 PlayerShoulders = CreateDefaultSubobject<USceneComponent>(TEXT("PlayerShoulders"));
 PlayerShoulders->AttachParent = CameraComponent;
 PlayerShoulders->RelativeLocation = FVector(0.0f, 0.0f, 0.0f);
 
 PlayerArms = CreateDefaultSubobject<USceneComponent>(TEXT("PlayerArms"));
 PlayerArms->AttachParent = PlayerShoulders;
 PlayerArms->RelativeLocation = FVector(0.0f, 0.0f, 0.0f);
 
 PlayerHand = CreateDefaultSubobject<USceneComponent>(TEXT("PlayerHand"));
 PlayerHand->AttachParent = PlayerArms;
 PlayerHand->RelativeLocation = FVector(30.0f, 0.0f, -20.0f);

The only way to fix this (that I have found) is to manually call UpdateChildTransforms() every frame (or at least the needed frames, as in when not moving). My guess is that UpdateChildTransforms() is called from the root only when the root transform is changed which I assume is optimization stuff, but it would be nice to have an option to force this or at least make it clear why this happens as it is a rather big assumption that if the root is stagnant no children can move and get updated properly.

Here is a video of the problem: Child scene components not updating properly Unreal Engine 4 - YouTube

Hey -

Looking at the code you posted I noticed that your PlayerBody doesn’t specify what the “CreateDefaultSubobject” is that it is being created. I’m surprised this isn’t causing a compile issue but since it is connected directly to the capsule (and everything else connects to it) it may have something to do with your issue. Additionally you may want to take a look at the Character header/source files for the First Person Template project since it has recoil on fire when standing still.

Cheers

Sorry about that, the missing stuff on PlayerBody was purely a cope/paste error, here is something more representative:

CapsuleComponent = CreateDefaultSubobject<UCapsuleComponent>(TEXT("CapsuleComponent"));
	CapsuleComponent->SetCapsuleSize(40.0f, 90.0f, true);
	RootComponent = CapsuleComponent;

	PlayerBody = CreateDefaultSubobject<USceneComponent>(TEXT("PlayerBody"));
	PlayerBody->AttachParent = CapsuleComponent;
	PlayerBody->RelativeLocation = FVector(0.0f, 0.0f, 0.0f);	

	CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComponent"));
	CameraComponent->AttachParent = PlayerBody;
	CameraComponent->RelativeLocation = FVector(0.0f, 0.0f, 75.0f);
	CameraComponent->bUsePawnControlRotation = false;

	PlayerShoulders = CreateDefaultSubobject<USceneComponent>(TEXT("PlayerShoulders"));
	PlayerShoulders->AttachParent = CameraComponent;
	PlayerShoulders->RelativeLocation = FVector(0.0f, 0.0f, 0.0f);

	PlayerArms = CreateDefaultSubobject<USceneComponent>(TEXT("PlayerArms"));
	PlayerArms->AttachParent = PlayerShoulders;
	PlayerArms->RelativeLocation = FVector(0.0f, 0.0f, 0.0f);

etc…

Yes,recoil when standing still works in the First Person Template but that is probably due to it being driven by animation and not Transform directly (at least I suspect that):

// try and play a firing animation if specified
	if(FireAnimation != NULL)
	{
		// Get the animation object for the arms mesh
		UAnimInstance* AnimInstance = Mesh1P->GetAnimInstance();
		if(AnimInstance != NULL)
		{
			AnimInstance->Montage_Play(FireAnimation, 1.f);
		}
	}

EDIT: One piece of information that might be needed, I am not using UsePawnControlRotation on the camera since it is not possible due to leaning mechanics involved when moving, the camera Y-rotation is also set in the Tick of the root actor/character.

Hey -

How exactly are you controlling the movement of your character (such as recoil and bobbing)? If possible could you post the source and header files for your character so that I can try using them in a project?

Here is an example:

//shooting weapon, move to weapon later on
	if (shoot || shooting)
	{   
		if (shootBack == 0.0f)
		{
                    shooting = true;
			UGameplayStatics::PlaySoundAtLocation(this, shootSound, GetRootComponent()->GetComponentLocation());
		}

		if (shootBack <= 0.1f)
		{
			shootBack += DeltaTime;
			PlayerArms->RelativeLocation.X = FMath::Lerp(0.0f, -15.0f, FMath::Min(1.0f, shootBack / 0.1f));
		}	
		else if (shootForward <= 0.15f)
		{
			shootForward += DeltaTime;
			PlayerArms->RelativeLocation.X = FMath::Lerp(-15.0f, 0.0f, FMath::Min(1.0f, shootForward / 0.15f));
		}
		else if (reloadDelay <= 0.5f)
		{
			reloadDelay += DeltaTime;
		}
		else
		{
			shooting = false;
			shootBack = 0.0f;
			shootForward = 0.0f;
			reloadDelay = 0.0f;			
		}
	}

Shoot gets set to true when pressing left mouse button.

Here is header/source files :

To display the problem comment out this in Tick:

PlayerBody->UpdateChildTransforms();

Might add that movement is a total mess at the moment but that is not related to this problem :slight_smile:

Hi ,

Thank you for providing the code for your character. I am working on recreating this issue, but I wanted to check and see if you are still seeing this happen in the released version of 4.8.

Just downloaded and tested, the problem is still present. I have however noticed that it works when attaching the weapon like this instead (the weapon is now a spawned separate actor and not included in the player hierarchy) :

void AWeapon::EquipWeapon(AQuakeCharacter *player, USceneComponent *hand)
{
	this->SetOwner(player);
	Player = player;
	this->SetActorTickEnabled(true);
	RootComponent->SetVisibility(true, true);
	this->AttachRootComponentTo(hand);	
	this->SetActorRelativeLocation(FVector::ZeroVector);
} 

Funny this is that attaching it this way forces the scene components to get updated as well, so shoulders, arms and hand moves as they should. Does AttachRootComponent flag something that forces them to update?

Hi ,

This is still a mystery to me after looking at your code as to why this would only be getting updated while moving, but from your latest post can I assume that this is a suitable work around for the issue? I am going to continue looking into why it is working any differently but I want to be sure that your issue is solved first.

Well, using either the method I last posted or forcing UpdateChildTransforms() from top component works, so it is OK in that regard. The major problem in my opinion that a user might be very confused and won’t know why it does not work since it all seemed very straight forward (nesting scene componenents does not seem to advanced), it threw me off for a week before going through all actor methods i detail and trying them out :slight_smile:

Updated to 4.8.1 and the problem is present again, only thing that fixes it is UpdateChildTransforms(), attaching no longer works.

Hi ,

I apologize for the time since my last response but I’m still having issues recreating the issue itself. Would it be possible for you to upload a copy of a working project that reproduces the issue at hand? If you wish for it to not be available to the public or if the size is simply too large, you could use a third party hosting site such as dropbox and link to the download here or through a private message to me on the forums. For reference, my forum username is .

Being able to reproduce the issue first-hand is the first step to getting the issue fixed and it would help a lot if you could provide this.

Thank you for providing the project. I’ve taken a look at your set up and I would suggest attempting to make the weapon into an ActorComponent instead of an Actor. I’m not exactly sure if this would fix the issue at hand and I’m still getting my head around the code but it was my first thought. In the meantime, can you point me into the direction of the function that causes the gun to recoil?

Yeah sorry, there has been some changes since this issue was reported, but the recoil is now in this part:

void AWeapon::Shoot(float DeltaTime)
{
	code...
}

But the easiest is probably to look at this part

void AQuakeCharacter::WeaponBob(float DeltaTime)
{

}

Especially this part (stand still and jump and the weapon will move up but gets stuck once you land, move and the gun is in the correct position, so the code values were changed but the visuals did not keep up):

//up/down movement of shoulders when jumping or falling
	if (!isGrounded)
	{
		float speed = CapsuleComponent->GetPhysicsLinearVelocity().Z;
		float modifier = speed / 500.0f; //change to jump speed
		modifier = FMath::Clamp(modifier, -1.0f, 1.0f);

		//PlayerShoulders->RelativeLocation.Z = -5.0f * modifier;
		PlayerShoulders->RelativeLocation.Z = FMath::FInterpTo(PlayerShoulders->RelativeLocation.Z, -5.0f * modifier, DeltaTime, 10.0f);
				
	}
	else
	{
		PlayerShoulders->RelativeLocation.Z = FMath::FInterpTo(PlayerShoulders->RelativeLocation.Z, 0.0, DeltaTime, 10.0f);
	}

Hi ,

After some digging around it dawned on me that you’re directly setting the RelativeLocation X/Y/Z instead of using SetRelativeLocation(). In this case, I believe it is not being updated due to that. Could you try using SetRelativeLocation() instead and see if that solves the issue for you?

Hope this helps!