Gameplay Framework — who owns what in Unreal
When people say "the player in Unreal", they really mean a cluster of six or seven objects, each with its own role. AActor is the base world object; everything else descends from it. APawn is an AActor that can be possessed by a controller (Possess). ACharacter is an APawn with a CapsuleComponent, SkeletalMeshComponent, and UCharacterMovementComponent already wired in. APlayerController is the player's "brain": input, camera, HUD. APlayerState is the player's replicated identity: score, name, team. AGameMode is the match rules and exists only on the server. AGameState is the replicated match state, visible to every client.
This role split isn't academic — it's the network contract. AGameMode doesn't replicate because rules are a server concern; a client must never be able to "decide it won". APlayerState replicates because score has to drive the scoreboard for everyone. APlayerController exists on the server and on the owning client only — other players don't see your input. APawn replicates as the visible body. Mixing those up is an instant fail on a networking interview.
Alongside this inheritance hierarchy, Unreal leans heavily on composition over inheritance via UActorComponent. Health, inventory, abilities, movement — all of those are components attached to an AActor. And sitting above all of this are USubsystems — singletons with explicit lifetimes (GameInstance, World, LocalPlayer, Editor) that replace the classic "manager of everything" pattern.
Topic map
- Actor Fundamentals —
AActor, lifecycle (BeginPlay→Tick→EndPlay→Destroy),SpawnActor,FActorSpawnParameters. - Pawn Control —
APawnvsACharacter, possession,OnPossess/OnUnPossess,SetupPlayerInputComponent. - Player Controller —
APlayerController, input, camera, HUD, outliving the Pawn across respawn. - Player State —
APlayerState, replicated identity,CopyPropertiesacross seamless travel. - GameMode (Authority) —
AGameMode/AGameModeBase, server-only, match rules, default classes. - GameState (Shared) —
AGameState/AGameStateBase, replicated to everyone, shared match state. - Character Movement —
UCharacterMovementComponent, movement modes, replication, client-side prediction. - Component Composition — actor as a set of components,
AttachToComponent, scene hierarchy. - Component Reuse — reusing components across classes,
ClassGroup,BlueprintSpawnableComponent. - Health Component — canonical health component pattern, replication,
OnDamagedelegate. - Damage System —
TakeDamage,DamageType,UGameplayStatics::ApplyDamage, damage modifiers. - Ability Cooldown — cooldown patterns: timestamp, GAS,
FTimerManager. - Subsystems —
UGameInstanceSubsystem,UWorldSubsystem,ULocalPlayerSubsystem,UEditorSubsystem.
Common traps
| Mistake | Consequence |
|---|---|
Believing APawn sits on a branch separate from AActor | APawn derives from AActor; a pawn is an actor with the possession capability |
Storing the player's score on APawn | The pawn dies on respawn — the score dies with it; score belongs on APlayerState |
Putting input/camera on APlayerState | PlayerState replicates to everyone; input is private and belongs on APlayerController |
Storing replicated state in AGameMode | AGameMode exists only on the server — clients can't see it; shared state belongs in AGameState |
Applying damage by direct subtraction Health -= Damage | Bypasses TakeDamage, DamageType, OnDamage — no modifiers, no events |
Counting cooldown inside Tick | Drifts with FPS; use GetWorld()->GetTimeSeconds() as a timestamp |
Treating AIController and APlayerController as interchangeable | Both descend from AController, but their roles and lifetimes are different |
Using NewObject<AActor>() instead of SpawnActor | The actor isn't registered with the world, no BeginPlay, no tick |
Binding input in a constructor instead of SetupPlayerInputComponent | Bindings created before play starts are discarded; handlers never fire |
| Trusting damage that the client sends as a number | Any client will send "a million"; the client sends intent, the server computes |
Treating AGameInstance and AGameMode as the same thing | AGameInstance lives for the whole process (across levels); AGameMode is recreated per match |
| Thinking you must manually create and register a Subsystem | The engine creates and owns subsystems; you only derive from the right base class |
Interview relevance
The Gameplay Framework is a baseline middle-level question for any UE5 gameplay-programmer interview. At junior+ they check:
- The hierarchy:
AActor→APawn→ACharacter; that a pawn is an actor with possession. - The Controller vs Pawn split: the controller thinks, the pawn expresses.
- Where the player's score lives:
APlayerState, not the pawn. - That
AGameModeis server-only andAGameStatereplicates. - That
APlayerControlleroutlives the pawn (respawn logic).
At middle/senior they go further:
CopyPropertiesfor migratingAPlayerStateacross seamless travel.- Why damage is routed through
ApplyDamage/TakeDamageinstead of direct subtraction. - Server-side damage validation (the client sends intent, never a damage number).
- Composition: when to extract a component vs leave logic on the actor.
- Subsystems: why they replace singleton-managers, and which scope fits which job.
Common wrong answer: "I store score on the Pawn because the Pawn is the player." The real answer is that the Pawn dies on respawn, and the score dies with it. The Pawn is the body, not the player. The player is the PlayerController + PlayerState cluster; the score belongs to the PlayerState.