Unreal Engine: Actors, Components, and Blueprints

·3 min read·Graham Mace
Unreal Engine: Actors, Components, and Blueprints

Following on from controllers and game modes, this week was about actors, components, and blueprints – the object model that underpins basically everything in Unreal.

As ever, I’ve been committing changes to the repository as I go – notes below.

sawnoff-studios/first-project

Game Objects: Renderable and Non-Renderable

Not everything in a level is something you can see. Useful mental split:

  • Renderable: enemies, players, pick-ups, props, projectiles, scenery
  • Non-renderable: waypoints, volumes, triggers, sounds

Inheritance vs Composition

Inheritance (“is a”):

  • Hierarchies can run deep, and a change at the top cascades all the way down
  • Multiple inheritance (one class, several parents) causes the “Deadly Diamond” problem: multiple copies of base class members can end up in one object
  • This is why most studios outright prohibit multiple inheritance; some permit it only if there’s a single grandparent at worst

Composition (“has a”):

  • The entity becomes a container for components rather than a chain of specialisations
  • This is the dominant paradigm in modern game engines – and it’s the model Unreal itself uses
  • Downsides: many components can slow things down, and tasks that need synchronised data often end up holding duplicate copies of it

The course’s example was building a Halftrack both ways – an illustration of how the same object falls out of inheritance versus composition.

Blueprints: Events, Functions, Pure Functions, Macros

The colour-coding of blueprint nodes tells you what kind of thing you’re looking at:

Events (red)

  • Fired by engine triggers (e.g. BeginPlay, Tick) – you don’t call them yourself
  • You can create custom events from the context menu
  • Can be replicated from the server for multiplayer
  • Blueprint functions and macros can be double-clicked to inspect their bodies

Functions (blue)

  • Declared through the Functions panel; called like any built-in function
  • Performance note: functions have a slight edge over events, because a function compiles into one batch of bytecode – whereas every node in an event graph is processed individually. In practice the bigger difference is structural (local scope, no latent actions), but it’s nice to know
  • Variables inside are local to the function
  • Access specifiers (public/protected/private) work just like in C++

Pure functions (green)

  • Like const-typed functions in C++: they take inputs, produce outputs, and have no side effects
  • Commonly seen feeding Branch conditions
  • Variables are local to the function as above

Macros (grey)

  • ForLoop, Sequence, and Branch are actually pre-defined macros, not functions
  • Sequence runs one section after another in order
  • You can define your own macros in the Macros panel, with defined inputs and outputs like functions
  • Macros can contain Delays (and other latent nodes), which functions cannot
  • Don’t edit the StandardMacros library; instead build a Blueprint Macro Library for custom reusable macros

Components

The composition half of this week’s theory, in practice:

  • Add components via the Components panel, or in C++:
    • Declare a TObjectPtr<> member (with a forward declaration in the header)
    • Initialise with CreateDefaultSubobject<>() in the constructor
    • Attach to a parent with SetupAttachment() – e.g. a mesh onto a capsule
    • Component classes and their headers are easy to find via the documentation search
  • CapsuleComponent – untick Hidden In Game to actually see it while playing
  • SpringArm - TargetArmLength sets the camera’s distance behind the pawn; Camera Lag Speed controls how fluidly the camera catches up
  • Vertical camera rotation again required Use Pawn Control Rotation on the camera/spring arm – the same gotcha from last week, biting me a second time

Notes on things that tripped me up

Two repeat offenders this week: the Use Pawn Control Rotation setting (which seems to bite everyone twice) and discovering that ForLoop and friends aren’t functions at all.

The functions-vs-events distinction also took a while to settle – my working summary: events react, functions compute, pure functions don’t touch state, macros are the escape hatch for Delays.