Tick Order Of Built-in Unreal Engine Types

Published October 7, 2021
In this article we will discuss tick order of following Actor/Component classes:
  • AController and its subclasses
  • APawn and its subclasses
  • UPawnMovementComponent and its subclasses
  • USkeletalMeshComponent
  • USpringArmComponent
All subclasses share the same tick order with its base class.
The tick order of these actor/components is demonstrated in the following graph, the rest of this article is an explanation of how this relationship is setup.
notion image

Tick Dependency

AController , APawn, UPawnMovementComponent and USkeletalMeshComponenthave tick group TG_PrePhysics, and USpringArmComponent has tick group TG_PostPhysics, so USpringArmComponent is ticked after the other ones.
USkeletalMeshComponent and UCharacterMovementComponent have some extra tick functions, we won’t discuss them here.
The tick order of AController, APawn, UPawnMovementComponent and USkeletalMeshComponent is setup by tick dependency.

AController, APawn and UPawnMovementComponent

// Controller.cpp void AController::AddPawnTickDependency(APawn* NewPawn) { if (NewPawn != NULL) { bool bNeedsPawnPrereq = true; UPawnMovementComponent* PawnMovement = NewPawn->GetMovementComponent(); if (PawnMovement && PawnMovement->PrimaryComponentTick.bCanEverTick) { PawnMovement->PrimaryComponentTick.AddPrerequisite(this, this->PrimaryActorTick); // Don't need a prereq on the pawn if the movement component already sets up a prereq. if (PawnMovement->bTickBeforeOwner || NewPawn->PrimaryActorTick.GetPrerequisites().Contains(FTickPrerequisite(PawnMovement, PawnMovement->PrimaryComponentTick))) { bNeedsPawnPrereq = false; } } if (bNeedsPawnPrereq) { NewPawn->PrimaryActorTick.AddPrerequisite(this, this->PrimaryActorTick); } } } // MovementComponent.cpp void UMovementComponent::RegisterComponentTickFunctions(bool bRegister) { Super::RegisterComponentTickFunctions(bRegister); // Super may start up the tick function when we don't want to. UpdateTickRegistration(); // If the owner ticks, make sure we tick first AActor* Owner = GetOwner(); if (bTickBeforeOwner && bRegister && PrimaryComponentTick.bCanEverTick && Owner && Owner->CanEverTick()) { Owner->PrimaryActorTick.AddPrerequisite(this, PrimaryComponentTick); } }
In AController::AddPawnTickDependency and UMovementComponent::RegisterComponentTickFunctions the following tick dependencies are setup:
  • AController is ticked before UPawnMovementComponent.
  • AController is ticked before APawn.
  • By default UPawnMovementComponent is ticked before its owning APawn. But you can turn off bTickBeforeOwner if the tick order doesn’t matter.

UpdatedComponent and UMovementComponent

void UMovementComponent::SetUpdatedComponent(USceneComponent* NewUpdatedComponent) { ... // Assign delegates if (UpdatedComponent) { ... // force ticks after movement component updates UpdatedComponent->PrimaryComponentTick.AddPrerequisite(this, PrimaryComponentTick); } UpdateTickRegistration(); if (bSnapToPlaneAtStart) { SnapUpdatedComponentToPlane(); } }
In UMovementComponent::SetUpdatedComponent, UpdatedComponent is setup to tick after UMovementComponent , by default UpdatedComponent is the root capsule component, but it can be assigned to other component at runtime.

USkeletalMeshComponent and UCharacterMovementComponent

void ACharacter::PostInitializeComponents() { QUICK_SCOPE_CYCLE_COUNTER(STAT_Character_PostInitComponents); Super::PostInitializeComponents(); if (!IsPendingKill()) { if (Mesh) { ... // force animation tick after movement component updates if (Mesh->PrimaryComponentTick.bCanEverTick && CharacterMovement) { Mesh->PrimaryComponentTick.AddPrerequisite(CharacterMovement, CharacterMovement->PrimaryComponentTick); } } ... } }
In ACharacter::PostInitializeComponents, USkeletalMeshComponent is setup to tick after UCharacterMovementComponent. Even without this rule a child USceneComponent is ticked after its parent USceneComponent.

USceneComponent Child and Parent

There is another rule in Unreal, USceneComponent child always ticks after its parent, this is setup in USceneComponent::AttachToComponent.
bool USceneComponent::AttachToComponent(USceneComponent* Parent, const FAttachmentTransformRules& AttachmentRules, FName SocketName) { ... if(Parent != nullptr) { ... // Detach removes all Prerequisite, so will need to add after Detach happens PrimaryComponentTick.AddPrerequisite(Parent, Parent->PrimaryComponentTick); // force us to tick after the parent does ... return true; } return false; }