Skip to content

Actor Components as reusable gameplay

When several actors need the same health, inventory, interaction, team, or status logic, an Actor Component is often the missing middle between "copy the variables" and "make a giant parent class."

The one-minute version

  • An Actor Component is a reusable object owned by an actor. It has variables, functions, events, dispatchers, and optional tick, but no transform.
  • Use one when the behavior belongs on many actor types but is not the actor's whole identity: health, inventory, interactability, team, lock state, sensor memory, status effects.
  • Do not use an Actor Component for something that needs a location, mesh, socket, collision shape, or camera. Use a Scene/Primitive Component or an Actor for that.
  • The component talks to its owning actor with Get Owner, interfaces, functions, and dispatchers. The owning actor should still decide actor-level actions such as destroying itself, playing body animations, or changing collision.
  • Widgets and other listeners usually bind to dispatchers on the component, then unbind or rebind when the owning actor changes.
  • In multiplayer, a component does not magically solve authority. Server-owned gameplay still belongs on the server, and replicated component state needs a replicated owning actor and correct component replication setup.

What an Actor Component is

An Actor Component is a UActorComponent instance that belongs to one actor. It is not placed separately in the level. It does not have its own world location. It lives and dies with its owning actor unless you create/destroy it manually at runtime.

BP_Enemy
-> HealthComponent
   - CurrentHealth
   - MaxHealth
   - ApplyDamage()
   - OnHealthChanged dispatcher
   - OnDeath dispatcher

The owning actor still exists as the visible game object. The component is the reusable health logic attached to that object.

That split is useful because health is not unique to one class. A player, enemy, destructible barrel, and boss weak point may all need "take damage, clamp health, broadcast changed, report dead" without sharing a parent class.

When a component beats copied variables

Copied variables are fine for one Blueprint. They become a maintenance problem when the same mini-system appears in many places.

Use an Actor Component when you notice this shape:

BP_Player has:
    Health, MaxHealth, ApplyDamage, OnDeath

BP_Enemy has:
    Health, MaxHealth, ApplyDamage, OnDeath

BP_Barrel has:
    Health, MaxHealth, ApplyDamage, OnDeath

Better:

BP_Player -> HealthComponent
BP_Enemy  -> HealthComponent
BP_Barrel -> HealthComponent

Now the damage/clamp/broadcast rules live in one component class. Each actor can still decide what death means:

  • player: disable input, show death UI, ask GameMode to restart;
  • enemy: stop AI, play montage, destroy after delay;
  • barrel: spawn effects, damage nearby actors, destroy itself.

The component owns the shared state. The actor owns the actor-specific result.

What it can do without a transform

An Actor Component can:

  • store values and object references;
  • define Blueprint functions;
  • receive BeginPlay and EndPlay;
  • tick if you enable component ticking;
  • bind to owner or world events;
  • call Get Owner;
  • call interfaces on the owner or other objects;
  • broadcast event dispatchers;
  • replicate properties when set up correctly on a replicated actor.

It cannot by itself:

  • be placed at a socket;
  • provide a collision volume;
  • render a mesh;
  • be the target of Set Actor Location;
  • appear as a separate actor in the World Outliner;
  • receive component overlap events unless a primitive component provides the collision and passes the event along.

If your "component" needs a visible position, start with a Scene Component or Primitive Component instead.

Owner communication

The component should not assume every owner is the same exact Blueprint class unless that is truly the contract.

Good communication options:

Need Pattern
Component needs basic actor data Get Owner, then use actor-level functions or interfaces.
Owner needs to react to component state Owner binds to component dispatchers or calls component functions directly.
Widget needs health updates Widget receives the component reference and binds to OnHealthChanged.
Other actor needs generic behavior Use a Blueprint Interface, such as BPI_Damageable or BPI_Interactable.
Component needs a specific owner class Cast once on BeginPlay, store the typed owner, and fail loudly with a print/assertion while developing.

For a health bar:

PlayerController creates WBP_HealthBar
-> gets current character
-> gets HealthComponent from character
-> widget binds to HealthComponent.OnHealthChanged
-> component broadcasts whenever health changes

When respawn replaces the pawn, the widget should unbind from the old component and bind to the new character's component. The component did its job; the player/UI ownership path still has to handle lifetime.

Component lifecycle

Designed components in the Components window are created with the actor. Runtime components can be added with Add Component by Class.

Important lifecycle points:

  1. Construction/defaults. Designed components exist on the class/instance setup path and can expose defaults in Details.
  2. BeginPlay. Component gameplay setup usually belongs here, after the owner is in the play world.
  3. Runtime add. A newly added component must be registered before it ticks, renders, or participates in the world. Blueprint's add-component path handles the normal finish/register step.
  4. EndPlay/destroy. Clear timers, unbind external listeners when needed, and broadcast shutdown only if your own design promises it.

Do not put heavy world searches in every component's Tick. If the component can react to overlap, damage, input, dispatcher, or owner events, make the event the entry point.

Failure modes

Actor Components fail mostly through bad assumptions:

Failure What it looks like Fix
Owner is not the class you assumed Cast failed, variables stay default, Accessed None later. Use an interface or validate/cast once and handle failure.
Component reference was never assigned Widget cannot bind; call target is None. Get the component from the current actor, pass it on creation, or make it Instance Editable for placed wiring.
Component has no transform You cannot attach it to a socket or use it for collision. Use Scene/Primitive Component or an Actor.
Runtime component not initialized for your pattern It exists but never starts its setup. Add through the normal node, call your own Initialize function, and avoid relying on editor-only setup.
Old actor was destroyed or respawned UI/listeners still point at the old component. Rebind when the current pawn/actor changes and guard with Is Valid.
Multiplayer authority is wrong Client changes local component value but server/other clients disagree. Make server authoritative; replicate the owning actor/component state intentionally.

Failure is not a try/catch path. Your component can be valid while your design is wrong, so debug with prints, breakpoints, and explicit owner checks.

The pattern everyone actually uses

Health component:

HealthComponent variables:
    MaxHealth
    CurrentHealth
    OnHealthChanged(Current, Max)
    OnDeath()

Function ApplyHealthDelta(Delta):
    Old = CurrentHealth
    CurrentHealth = Clamp(CurrentHealth + Delta, 0, MaxHealth)
    if CurrentHealth != Old:
        Call OnHealthChanged
    if Old > 0 and CurrentHealth == 0:
        Call OnDeath

Owning actor:

BeginPlay
-> bind HealthComponent.OnDeath to HandleDeath

HandleDeath
-> disable collision/input/AI as appropriate
-> play effects
-> Destroy Actor or ask GameMode to respawn

Widget:

SetHealthSource(NewHealthComponent)
-> unbind old source if valid
-> bind new source OnHealthChanged
-> update once from current values

The component is reusable because the actor-specific death behavior is not hard-coded inside it.

Lookalikes - which one do I want?

Tool Use when Watch out
Actor Component Reusable behavior/data with no transform. Needs explicit communication with owner/listeners.
Scene Component Reusable part needs a transform or attachment point. Does not render/collide by default.
Primitive Component Reusable part needs mesh/collision/physics. More expensive and visually/spatially specific.
Parent Blueprint class Actors really are the same kind of thing and share identity. Single inheritance gets awkward when unrelated actors need one feature.
Blueprint Interface Many objects expose the same callable contract. Interface stores no shared state by itself.
Event Dispatcher Component broadcasts a state change to listeners. Listeners must bind/unbind around lifetime.
Data Asset Shared static tuning/configuration. It is data, not per-actor runtime state.

Rule of thumb: if you are about to paste the same variables and functions into three unrelated actors, try an Actor Component before making a bigger parent class.

Going deeper