Skip to content

Objective and Wave Manager Actors vs GameMode/GameState

A manager actor is a named coordinator in the level: "this arena wave," "this generator objective," "this checkpoint route." It is not a dumping ground for every global variable in the project.

The one-minute version

  • Use a placed manager actor when the system coordinates placed actors in a level: generators, levers, doors, spawn points, race checkpoints, puzzle pieces, room enemies, reward spawns, or music/combat phases.
  • Use GameMode when the system is a rule authority: can the match start, should score count, can the player respawn, did this objective end the game, which pawn class should spawn?
  • Use GameState when the result is public runtime state: wave number, objective progress, team score, match phase, remaining enemies, current winner, or any value clients and HUDs should read.
  • Use Level Blueprint for one-off map choreography, not reusable objective systems. If the graph has a name, state, reset logic, and several assigned references, it probably wants a manager actor.
  • Managers should find participants deliberately: editable arrays, registration events, gameplay tags, or a one-time BeginPlay search for small maps. Do not hide repeated Get All Actors Of Class calls in Tick or widget bindings.
  • In multiplayer, the server owns the manager's gameplay decisions. Clients read replicated manager/GameState data and run local presentation.

What a manager actor is

A manager actor is just an Actor Blueprint with a coordination job.

BP_ArenaWaveManager placed in L_CaveArena
    SpawnPoints: array of TargetPoint references
    EnemyClasses: array of enemy class references
    CurrentWave: integer
    AliveEnemies: set of enemy actor references
    OnWaveChanged dispatcher

It exists in the world, can be selected in the editor, can expose references in the Details panel, and can print/debug like any other actor. The value is not that it is magic. The value is that the coordination has one visible owner instead of being hidden in a map graph, widget, pawn, or GameMode variable pile.

Good manager jobs:

  • "All three generators repaired opens the vault."
  • "Spawn wave 4 when wave 3 enemies are dead."
  • "Track race checkpoints for this route."
  • "When this room puzzle completes, unlock this door and spawn this reward."
  • "This boss arena changes phase when weak points are disabled."

Poor manager jobs:

  • the player's movement or input graph;
  • global save profile data;
  • every objective in the entire game;
  • all UI button logic;
  • health math for every enemy;
  • match rules clients need to read but the manager does not replicate.

The decision table

Put it here Use when Warning sign
Level Blueprint One map, one-off choreography, Sequencer, streaming trigger, a single placed reference script. The graph is copied into another map or has a reusable system name.
Objective / wave manager actor A named level system coordinates participants and may be reused as a class. It starts owning unrelated systems or hidden global state.
Participant actor / component A generator, door, checkpoint, enemy, or spawner owns its own local behavior. A manager directly edits every tiny internal variable instead of calling clear functions/events.
GameMode Server rules, scoring decisions, respawn, match start/end, objective completion meaning. A client widget needs to read its variables.
GameState Public match/objective summary everyone should read. It starts holding editor-assigned references to every room object.
PlayerState Per-player progress/score/team/ready state. The value belongs to the room, team, or match instead of one player.
GameInstance / SaveGame Cross-level temporary data or durable completed-objective records. You store live actor references from the current map.

The manager is the middle layer: close enough to the map to own placed references, but named and reusable enough to avoid a giant Level Blueprint.

Example: generator objective

Each generator owns being repaired:

BP_Generator
    bRepaired
    OnRepaired dispatcher
    Repair() function

The manager owns the group rule:

BP_GeneratorObjectiveManager
    Generators: array of BP_Generator references
    RequiredCount: integer
    CompletedCount: integer
    VaultDoor: BP_Door reference

BeginPlay:
    for each Generator:
        bind Generator.OnRepaired to HandleGeneratorRepaired
    RefreshObjectiveSummary

HandleGeneratorRepaired(Generator):
    if Generator already counted:
        return
    mark counted
    CompletedCount += 1
    RefreshObjectiveSummary
    if CompletedCount >= RequiredCount:
        CompleteObjectiveOnce()

Completion can then touch the wider framework deliberately:

CompleteObjectiveOnce:
    if bCompleted:
        return
    bCompleted = true
    VaultDoor.OpenDoor()
    GameState.ObjectiveSummary = "Generators complete"
    GameMode.ObjectiveCompleted(self)

The generator does not know the whole mission. The door does not know the score rules. The manager coordinates the room. GameMode decides what the completion means for the game.

Example: wave manager

A wave manager is useful because spawn points, enemy classes, wave state, and enemy-death subscriptions all belong to this arena.

BP_WaveManager
    WaveDefinitions: array of FWaveDefinition
    SpawnPoints: array of TargetPoint references
    CurrentWaveIndex
    AliveEnemies: set of Actor references
    bWaveActive

StartNextWave:
    CurrentWaveIndex += 1
    for each enemy entry in WaveDefinitions[CurrentWaveIndex]:
        choose SpawnPoint
        Spawn Actor from Class
        bind enemy OnDeath to HandleEnemyDied
        add enemy to AliveEnemies
    GameState.WaveNumber = CurrentWaveIndex + 1
    GameState.RemainingEnemies = AliveEnemies length

HandleEnemyDied(Enemy):
    remove Enemy from AliveEnemies
    GameState.RemainingEnemies = AliveEnemies length
    if AliveEnemies is empty:
        FinishWaveOnce()

If wave completion awards score or ends the match, GameMode should validate and apply that rule. If the HUD displays wave and enemy count, GameState should hold the public values or the manager itself must replicate those values clearly.

How managers find participants

Use the least surprising reference strategy that fits the level.

Strategy Use when Caveat
Editable references in Details A designer can assign the exact doors, levers, generators, or spawn points. Missing assignments produce None; validate on BeginPlay.
Participants register with manager Actors spawn dynamically or stream in and can find the manager once. Needs unregister on EndPlay and duplicate guards.
Gameplay tags or component tags The manager needs "all generators tagged Objective.A" in one area. Tags classify; they do not replace validation or ownership.
One-time BeginPlay search A small map has a few known actors and no streaming complication. Do not repeat the search every frame or from widgets.
Expose on Spawn A spawner creates participants and passes the manager reference immediately. Spawned actors still need to handle manager destruction/endplay.

Validate early:

BeginPlay:
    if Generators is empty:
        Print warning "GeneratorObjective has no generators"
    for each Generator:
        if not Is Valid:
            Print warning with manager name and missing index

A variable typed BP_Door is not an assigned door. The manager still needs a real actor reference.

Communication shape

Use functions for commands and dispatchers for announcements:

Manager -> Door:
    OpenDoor()

Generator -> Manager:
    OnRepaired broadcast

Enemy -> Manager:
    OnDeath broadcast

Manager -> UI/GameState:
    update public ObjectiveSummary
    broadcast OnObjectiveChanged locally if useful

Avoid making the manager reach through every participant's internals:

Manager:
    Generator.bRepaired = true
    Generator.Mesh.SetMaterial(...)
    Generator.Audio.Stop()

Prefer:

Manager:
    Generator.SetRepairedByObjective()

The participant owns its own presentation and local state. The manager owns the group rule.

Reset and replay

Objectives and waves often need a reset path for death, retry, checkpoint load, level restart, or editor testing.

Write a real reset function:

ResetObjective:
    bCompleted = false
    CompletedCount = 0
    CountedGenerators empty
    for each Generator:
        Generator.ResetGenerator()
    VaultDoor.CloseDoor()
    RefreshObjectiveSummary()

Do not rely on Open Level as your only reset if the game supports retrying a room, respawning in place, or streaming the area without full travel.

For a wave manager:

ResetWaves:
    destroy or despawn live enemies owned by this manager
    clear AliveEnemies
    CurrentWaveIndex = -1
    bWaveActive = false
    RefreshObjectiveSummary()

The manager should also clean up event bindings and live references in EndPlay when it has bound to long-lived actors or systems.

Save and load

Save plain objective facts, not live objects:

FSavedObjectiveState
    ObjectiveId
    bCompleted
    CompletedParticipantIds
    CurrentWaveIndex
    RemainingWaveSeedOrCount

On load:

Manager BeginPlay
-> ObjectiveId matches saved record
-> assign current-map participants by ID/reference setup
-> apply saved completed state
-> rebuild public GameState summary

Do not save actor references, timer handles, widget references, or spawned enemy object pointers. Those belong to the old world. Store stable IDs and rebuild current-world references after the map loads.

Replication

In a networked game, a manager actor is still an actor. If clients need to see its state directly, the manager must replicate and its variables must be replicated deliberately. Many beginner projects are cleaner if the manager updates GameState for public HUD facts:

Server BP_WaveManager:
    owns AliveEnemies and spawn decisions
    updates BP_MatchGameState.WaveNumber
    updates BP_MatchGameState.RemainingEnemies

Clients:
    read GameState values
    update HUD, music, markers, and local presentation

Use replicated manager state when the manager itself is a relevant gameplay actor clients inspect, such as a capture zone, payload, or objective marker. Use GameState when the value is a match-wide summary.

Rules that prevent most replication bugs:

  • spawn gameplay enemies and objective actors on the server when everyone should see them;
  • let clients request interaction through an owned server path;
  • change objective truth on the server;
  • replicate current state for late joiners, not only past events;
  • do not create widgets inside GameMode or replicated managers for remote clients;
  • print authority and net mode from the manager while debugging.

Avoid the hidden god Blueprint

A manager actor should have one named responsibility.

Good names:

  • BP_ArenaWaveManager
  • BP_GeneratorObjectiveManager
  • BP_RaceCheckpointManager
  • BP_RoomPuzzleManager
  • BP_BossPhaseManager

Warning names:

  • BP_GameManager
  • BP_LevelManager
  • BP_EverythingController
  • BP_GlobalLogic

The name does not prove the design is wrong, but it is a useful smell. If the manager handles waves, inventory, pause menu, save slots, player input, UI, enemy health, weather, and level travel, it is no longer a manager for one objective. Split it by owner and audience.

Failure modes

Symptom Likely cause
Objective never completes A participant reference is unassigned, registered too late, or never fired its dispatcher.
Completion runs twice The manager lacks a bCompleted or counted-participant gate.
Works in one copied map but not another Level Blueprint or manager instance references still point at the old map assumptions.
HUD shows stale progress UI cached a value instead of reading manager/GameState updates.
Client sees a wave number but enemies do not exist Enemies were spawned only on a client, or replicated actors are not relevant/spawned by server.
Late-joining client sees no objective Current objective state was only broadcast as an event, not stored as replicated state.
Reset leaves old enemies or bindings Reset cleared counters but did not clean live actors, timers, or dispatcher bindings.
Save/load points at destroyed actors Save data stored actor references instead of stable IDs/plain values.
Manager becomes impossible to debug It owns unrelated global systems instead of one named coordination job.

Print manager name, objective ID, authority, participant count, completed count, current phase, and bound actor names. Most failures are missing references, duplicate events, wrong machine, or state living only in UI.

The pattern everyone actually uses

Room objective:

BP_RoomPuzzleManager placed in the level
-> editable array of BP_Lever references
-> editable BP_Door reference
-> BeginPlay binds each Lever.OnStateChanged
-> HandleLeverChanged recomputes "all active"
-> CompleteObjectiveOnce opens door and updates GameState
-> GameMode receives ObjectiveCompleted if this affects score/win/loss

Wave arena:

BP_WaveManager placed in arena
-> editable SpawnPoints and WaveDefinitions
-> StartWave spawns server-owned enemies
-> each enemy OnDeath removes it from AliveEnemies
-> GameState.WaveNumber / RemainingEnemies refresh
-> wave complete starts delay or asks GameMode to end/check score

Race checkpoints:

BP_RaceCheckpointManager
-> ordered checkpoint actors register or are assigned
-> PlayerState stores current checkpoint index per player if public
-> GameState stores race phase / winner / public timer
-> GameMode validates finish and awards result

Lookalikes - which one do I want?

Tool Use when It does not
Level Blueprint One-off map sequence or placed actor glue that will not be reused. Create a reusable class or clean manager API.
Objective / wave manager actor A named level system coordinates participants and exposes designer references. Replace GameMode, GameState, PlayerState, SaveGame, or every actor's own behavior.
GameMode Server rule authority: scoring, win/loss, start/end, respawn. Replicate variables to remote clients.
GameState Public match/objective summary clients and UI should read. Hold every placed actor reference or run all local room logic.
Actor Component The same participant behavior belongs on many actor classes. Coordinate a whole room by itself unless that is truly its job.
Blueprint Interface Participants expose a shared contract such as ResetObjectiveParticipant. Store shared state or broadcast changes by itself.
Event Dispatcher Participants announce repair/death/activated state to the manager. Find references or guarantee lifetime without binding/unbinding.
Get All Actors Of Class One-time discovery for small maps or editor tools. Replace assigned references, registration, or per-frame state ownership.

Rule of thumb: participants own their local behavior, managers coordinate the level objective, GameMode decides game rules, GameState exposes public state, and UI presents what those owners already know.

Going deeper