| name | unreal |
| description | Use when building, scripting or debugging a game in Unreal Engine 5 with Blueprint or C++ โ the gameplay framework (Actor, Pawn, Character, GameMode, PlayerController), Actor lifecycle and tick, the reflection macros and garbage collection, Enhanced Input, multicast delegates, UMG widgets, Paper2D, and Blueprint-to-C++ parity in both directions. NOT Godot (that is `godot`), NOT Unity or MonoBehaviour (that is `unity`), NOT language-only C++ memory and RAII questions with no Unreal types (that is `cpp`). |
| tags | ["unreal","ue5","blueprint","unreal-engine","gamedev"] |
| recommends | ["cpp","gamedev-shipping","gamedev-multiplayer","game-design","gamedev-physics","godot","unity"] |
| profiles | ["full"] |
| origin | risco |
Unreal Engine 5 (Blueprint + C++)
Build and debug UE5 games with the grain of the engine: the Gameplay Framework for structure,
reflection macros so C++ and Blueprint see the same types, Enhanced Input for controls, UMG for
UI, Paper2D for 2D โ and a clean BlueprintโC++ boundary so either can call the other. Hands
3D-only concerns (shaders, physics, netcode, shipping) to the siblings below.
Version contract โ read first
Target Unreal Engine 5.x (patterns valid 5.3+; current stable UE 5.8, the last UE5 line
before UE6). Emit modern UE5 APIs only. Never emit these deprecated / legacy patterns:
| Never emit | Use instead (UE5) |
|---|
Legacy input: Project-Settings Action/Axis Mappings + InputComponent->BindAction/BindAxis(FName,โฆ) | Enhanced Input: UInputAction + UInputMappingContext + UEnhancedInputComponent->BindAction(โฆ), context added via UEnhancedInputLocalPlayerSubsystem (default since 5.1; legacy deprecated 5.2) |
Raw UObject* / AActor* as a UPROPERTY member | TObjectPtr<T> for UPROPERTY members (raw T* is fine for locals/params) |
GENERATED_UCLASS_BODY() | GENERATED_BODY() |
TAssetPtr<T> / FStringAssetReference | TSoftObjectPtr<T> / FSoftObjectPath |
ANY_PACKAGE in FindObject / StaticLoadObject | explicit package or FTopLevelAssetPath |
Slate/Canvas DrawText/HUD for game UI | UMG (UUserWidget) |
AGameMode as the default base for a solo game | AGameModeBase (use AGameMode only when you need MatchState/multiplayer login flow) |
DECLARE_MULTICAST_DELEGATE for a Blueprint-bindable event | DECLARE_DYNAMIC_MULTICAST_DELEGATEโฆ + BlueprintAssignable |
bCanEverTick = true "just in case" | leave tick off; drive logic from events/overlaps/timers (FTimerManager) |
| Hard-referencing / loading heavy assets at runtime by path | soft refs + FStreamableManager async load (hard refs only via ConstructorHelpers in the constructor) |
Blueprint vs C++ โ and the hybrid. Blueprint: designer-facing tweaks, per-level scripting,
UI wiring, rapid iteration, one-off actors. C++: core systems, performance-critical/tick-heavy
code, base classes, math, anything you want unit-tested or diffable in git. Default to the
hybrid: write the base class in C++ (UCLASS(Blueprintable)), expose tunables with
UPROPERTY(EditAnywhere, BlueprintReadWrite) and hooks with BlueprintImplementableEvent /
BlueprintNativeEvent, then create a Blueprint subclass for designers to set defaults, wire
assets, and script the specifics โ C++ speed and testability with Blueprint iteration.
Gameplay Framework โ who owns what
| Class | Responsibility | Lifetime / scope |
|---|
AActor | Anything placeable/spawnable in a level; holds components. | Per instance in a level/world |
UActorComponent / USceneComponent | Reusable behavior/data on an Actor; USceneComponent adds a transform. | Owned by its Actor |
APawn | An Actor that can be possessed and driven by a controller. | Per instance |
ACharacter | A Pawn with a CapsuleComponent, SkeletalMesh, and CharacterMovementComponent (walk/jump/crouch, networked). | Per instance |
AController / APlayerController / AAIController | The "brain" that possesses a Pawn; APlayerController maps a human player to input, camera, and UI. | One per player/AI |
APlayerState | Per-player replicated state that must survive respawn (name, score, team). | One per player |
AGameModeBase | The rules of the match; spawns players, defines default Pawn/Controller/HUD classes. Server-only โ never exists on clients. | One per level |
AGameStateBase | Game-wide replicated state all clients need (match phase, shared score, player array). | One, replicated |
AHUD / UUserWidget | On-screen UI; prefer UMG UUserWidget over AHUD canvas drawing. | Per PlayerController |
Rule of thumb: transient input/camera โ PlayerController; persistent per-player data โ
PlayerState; match rules โ GameMode (server); shared world state โ GameState. Full
responsibilities and a spawn-order diagram โ references/gameplay-framework.md.
Actor lifecycle, components & attachment
Order for a spawned/placed Actor: constructor (set defaults, create subobjects โ never
gameplay logic) โ PostInitializeComponents โ BeginPlay (world is live; safe to start logic)
โ Tick(DeltaSeconds) each frame (only if enabled) โ EndPlay / Destroyed (release).
AMyActor::AMyActor()
{
PrimaryActorTick.bCanEverTick = false;
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
Mesh->SetupAttachment(RootComponent);
}
void AMyActor::BeginPlay() { Super::BeginPlay(); }
- Create components with
CreateDefaultSubobject<T>(TEXT("Name")) in the constructor; store
them in a UPROPERTY() TObjectPtr<T> so they're kept alive and visible.
- Attach in the constructor with
SetupAttachment; at runtime use
AttachToComponent(Parent, FAttachmentTransformRules::SnapToTargetNotIncludingScale).
- Prefer timers over tick for periodic work:
GetWorldTimerManager().SetTimer(Handle, this, &AMyActor::Fn, 1.f, true);
Reflection macros & garbage collection
Macros register types with Unreal Header Tool (UHT) so they get GC, serialization, editor, and
Blueprint support. Put GENERATED_BODY() first inside the class.
UENUM(BlueprintType)
enum class ETeam : uint8 { Red, Blue };
USTRUCT(BlueprintType)
struct FLoadout { GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite) int32 Ammo = 30;
};
UCLASS(Blueprintable)
class MYGAME_API AWeapon : public AActor {
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Combat") float Damage = 10.f;
UPROPERTY(VisibleAnywhere) TObjectPtr<UStaticMeshComponent> Mesh;
UFUNCTION(BlueprintCallable, Category="Combat") void Fire();
};
Common UPROPERTY specifiers: EditAnywhere (edit on instances + defaults),
EditDefaultsOnly (class defaults only), VisibleAnywhere (read-only in editor);
BlueprintReadWrite (get + set in BP) vs BlueprintReadOnly (get only); always give a
Category.
Garbage collection โ the #1 gotcha. The GC frees any UObject that no reachable UPROPERTY
points to. A UObject reference stored without UPROPERTY() is invisible to GC: it will be
collected out from under you and the pointer dangles/crashes. So:
- Store every long-lived
UObject/AActor reference in a UPROPERTY() TObjectPtr<T>.
- For a non-owning "might already be dead" reference (don't keep it alive, must null-check), use
TWeakObjectPtr<T> and .IsValid().
- Never
new/delete a UObject โ spawn Actors with SpawnActor<T>() and create other UObjects
with NewObject<T>(); the GC owns their lifetime. new/delete and smart pointers apply only
to non-UObject C++ types.
Delegates & events
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHealthChanged, float, NewHealth);
UPROPERTY(BlueprintAssignable, Category="Events")
FOnHealthChanged OnHealthChanged;
OnHealthChanged.AddDynamic(this, &AMyActor::HandleHealth);
OnHealthChanged.Broadcast(NewHealth);
Use a dynamic multicast delegate whenever Blueprint must bind to the event (BlueprintAssignable);
its handler must be a UFUNCTION. Use a plain DECLARE_MULTICAST_DELEGATEโฆ (bind with
AddUObject/AddLambda) only for C++-to-C++ events that never touch Blueprint. Overlap/hit
events (OnComponentBeginOverlap, OnActorHit) are already dynamic multicast โ bind with
AddDynamic.
Blueprint โ C++ parity
Same graph, two languages. Left = the Blueprint node; right = the C++ that does the same thing.
| Blueprint node | C++ |
|---|
| Event BeginPlay | virtual void BeginPlay() override; (call Super::BeginPlay()) |
| Event Tick (Delta Seconds) | virtual void Tick(float DeltaSeconds) override; |
| Spawn Actor from Class | GetWorld()->SpawnActor<AWeapon>(Class, Loc, Rot); |
Cast To X | if (AX* P = Cast<AX>(Obj)) { โฆ } (always null-check) |
| Set Timer by Event | GetWorldTimerManager().SetTimer(H, this, &A::Fn, Rate, bLoop); |
| Print String | UE_LOG(LogTemp, Warning, TEXT("v=%d"), V); / GEngine->AddOnScreenDebugMessage(...) |
| Get Player Controller | UGameplayStatics::GetPlayerController(this, 0); |
Bind Event to OnClicked | Button->OnClicked.AddDynamic(this, &U::Fn); |
Expose C++ โ Blueprint:
UFUNCTION(BlueprintCallable, Category="X") void DoThing();
UFUNCTION(BlueprintPure, Category="X") int32 GetScore() const;
UPROPERTY(EditAnywhere, BlueprintReadWrite) float Speed = 600.f;
Call Blueprint โ C++ (the hybrid hooks โ declare in C++, implement/override in the BP subclass):
UFUNCTION(BlueprintImplementableEvent) void OnScored(int32 Points);
UFUNCTION(BlueprintNativeEvent) void OnDamaged(float Amount);
void AMyActor::OnDamaged_Implementation(float Amount) { Health -= Amount; }
Mapping table (every specifier), full expose/override examples, and the C++-base-+-BP-subclass
workflow โ references/blueprint-cpp-parity.md.
UMG (UI)
UI is a UUserWidget (design the visuals in a WBP asset; drive logic in C++ or its BP graph).
Bind C++ members to named widgets with meta=(BindWidget) โ the C++ name must match the WBP
widget.
UCLASS() class UHealthWidget : public UUserWidget { GENERATED_BODY()
UPROPERTY(meta=(BindWidget)) TObjectPtr<UProgressBar> HealthBar;
UFUNCTION(BlueprintCallable) void SetHealth(float Pct);
};
UHealthWidget* W = CreateWidget<UHealthWidget>(PC, WidgetClass);
W->AddToViewport();
Layout with panels (Canvas/V-H Box/Overlay/Grid); SetVisibility,
RemoveFromParent to hide/close; anchors + a design resolution for scaling.
Paper2D (2D)
Enable the Paper2D plugin. Core types:
- Sprite (
UPaperSprite asset, UPaperSpriteComponent) โ a single textured quad.
- Flipbook (
UPaperFlipbook asset, UPaperFlipbookComponent) โ frames + FPS = animation;
SetFlipbook(...) to swap states (idle/run/jump).
APaperCharacter โ a ACharacter whose mesh is a flipbook; you get
CharacterMovementComponent (walk/jump) for free, driven by Enhanced Input just like 3D.
- Tile maps (
UPaperTileMap, UPaperTileMapComponent) for level geometry.
2D uses the same Gameplay Framework, Enhanced Input, and lifecycle as 3D โ only the visual
components differ. Constrain movement to a plane and use an orthographic camera.
Packaging & build config (brief)
- Build configurations:
Debug, DebugGame, Development (default for iteration โ
optimized engine, hot-reloadable game code), Shipping (fully optimized, logging/console
stripped โ ship this), Test.
- Target files (
*.Target.cs) define Game/Editor/Client/Server targets; module rules
(*.Build.cs) declare module dependencies (e.g. "EnhancedInput", "UMG", "Paper2D").
- Package from Platforms โธ โธ Package Project, or automate with
RunUAT BuildCookRun (cook content โ stage โ package). Per-platform settings live in
Config/DefaultGame.ini / Default<Platform>Engine.ini.
This is the minimum. Deep shipping โ cooking, pak/IoStore, certification, size/perf budgets, CI โ
is owned by gamedev-shipping. Overview + a starter .Build.cs โ
references/packaging.md.
Guardrails & gotchas
- UPROPERTY-or-GC'd: any UObject ref you keep must be a
UPROPERTY() or it will be garbage
collected and crash. This is the most common Unreal C++ bug.
- Enhanced Input only โ no legacy Action/Axis mappings; add the
UInputMappingContext via the
local player subsystem in BeginPlay/on-possess, bind actions on UEnhancedInputComponent.
- GameMode is server-only โ never read it on a client; put client-visible state on GameState
or PlayerState and replicate.
- No gameplay in the constructor โ the world isn't ready. Do it in
BeginPlay.
- Always null-check
Cast<T>() and SpawnActor results; they can return nullptr.
- Don't
new/delete UObjects โ NewObject/SpawnActor and let GC free them. Header
changes need a full editor recompile (Live Coding covers .cpp bodies only).
- Regenerate project files after adding classes/modules; add module deps in
*.Build.cs
(missing "EnhancedInput"/"UMG" = linker errors).
- Multiplayer: replicate state with
UPROPERTY(Replicated), gate server actions behind
HasAuthority() โ see gamedev-multiplayer.
Related skills
cpp โ plain C++/RAII/smart-pointer ownership for non-UObject code; this
skill owns the Unreal reflection + GC model layered on top.
gamedev-shipping โ deep cooking/packaging/store submission.
gamedev-multiplayer โ replication, RPCs, authority.
gamedev-physics โ Chaos physics, collision, constraints.
game-design โ mechanics/loops before you build them.
godot / unity โ the other engines; route there
when the project is Godot or Unity, not Unreal.
Checklist