Files
UE5-Modular-Game-Framework/docs/blueprints/10-adaptive/92_BPC_ProceduralEncounter.md
Lefteris Notas 411edea8ce add blueprints
2026-05-19 13:22:27 +03:00

12 KiB
Raw Blame History

70 — BPC_ProceduralEncounter

Blueprint Spec — UE 5.55.7


Parent Class

ActorComponent

Dependencies

Purpose

Procedurally generates enemy encounters, ambushes, and spawn events based on player state, difficulty, fear level, atmosphere, and narrative progression. Operates as a tactical encounter director that decides when, where, and what enemies to spawn, how they behave, and when to retreat or reinforce. Prevents encounter fatigue by managing cooldowns, variety, and pacing. Supports wave-based encounters, ambushes, patrol reinforcement, and boss encounters.

Enums

EEncounterType

Value Description
Patrol Wandering enemy, player can evade
Ambush Pre-placed enemies triggered by player
WaveBased Multiple waves of increasing difficulty
Reinforcement Enemies called in during combat
Boss Single powerful enemy
Escalation Increasing intensity until player leaves area
Environmental Hazard-based encounter (not enemies)
Scripted Level designer placed encounter

ESpawnMethod

Value Description
FromLocations Use pre-placed spawn points
FromNavMesh Random point on nav mesh
FromVolumes Spawn in volume bounds
FromPortals Enemy emerges from gate/door
FromVent Spawn at vent locations
CeilingDrop Enemy drops from above
ClosestNav Closest valid nav point to player

EEncounterIntensity

Value Description
Low 12 weak enemies
Moderate 23 standard enemies
High 35 mixed enemies
Critical 5+ enemies with elites
Boss Single boss enemy

Structs

FEncounterSpawnSlot

Field Type Description
SpawnLocation FVector World position
EnemyClass TSubclassOf<BP_EnemyBase> Enemy to spawn
SpawnDelay Float Delay before this enemy appears
bDropIn Bool Animated drop-in
SpawnEffect UNiagaraSystem Visual spawn effect
PatrolRouteIndex Int32 Patrol path to follow

FEncounterWave

Field Type Description
WaveName FName Identifier
SpawnSlots TArray<FEncounterSpawnSlot> Enemies in this wave
ActivationDelay Float Time before wave starts
bWaitForAllDead Bool Next wave waits for all dead
DifficultyMultiplier Float Wave-specific difficulty
DialogueTrigger FName Optional dialogue on wave start

Variables

Name Type Description
ActiveEncounterType EEncounterType Current encounter type
EncounterState FName Active, Cooldown, Completed
bPlayerInEncounterZone Bool Player proximity trigger
EncounterRadius Float Zone size
MinEnemyDistance Float Min distance from player to spawn
MaxConcurrentEnemies Int32 Hard limit on active enemies
ActiveEnemies TArray<BP_EnemyBase> Currently alive enemies
Waves TArray<FEncounterWave> Defined waves
CurrentWaveIndex Int32 Active wave
bWaveInProgress Bool Currently executing wave
CooldownRemaining Float Encounter cooldown
MinCooldown Float Min time between encounters
MaxCooldown Float Max time between encounters
EncounterCount Int32 Encounters this session
MaxEncountersPerZone Int32 Encounters before exhaustion
bZoneExhausted Bool No more encounters in this zone
SpawnLocations TArray<FEncounterSpawnSlot> Configured spawn points
bUseNavMesh Bool Use nav mesh for spawns
EncounterVolumeBox FBox Spawn volume bounds

Functions

Name Inputs Outputs Description
Initialize Register spawn points, validate setup
TriggerEncounter Type: EEncounterType, Intensity: EEncounterIntensity Start encounter
TriggerWaveBasedEncounter Intensity: EEncounterIntensity Multi-wave encounter
SpawnWave WaveIndex: Int32 Execute wave spawning
SpawnSingleEnemy Slot: FEncounterSpawnSlot BP_EnemyBase Spawn one enemy
GetRandomSpawnLocation FVector Pick valid spawn point
GetSpawnLocationByMethod Method: ESpawnMethod FVector Contextual spawn position
OnEnemyKilled Enemy: BP_EnemyBase Track enemy death
OnAllEnemiesDead Wave completed or encounter ended
ReinforceEncounter Count: Int32 Spawn additional enemies
EndEncounter Cleanup and cooldown
RetreatEnemies All enemies flee
CalculateIntensity EEncounterIntensity Based on difficulty + fear + atmosphere
IsSpawnLocationValid Location: FVector Bool Check line of sight, nav mesh
IsInEncounterZone PlayerLocation: FVector Bool Proximity check
StartCooldown Begin cooldown timer
ExhaustZone Mark zone as depleted
ResetEncounter Full reset for reuse

Blueprint Flow

[Initialize]
  └─► Register spawn point locations from child actors or volume
  └─► If bUseNavMesh:
         Get nav mesh bounds from EncounterVolumeBox
  └─► Listen for player proximity via overlap events
  └─► Set initial EncounterState = Ready

[TriggerEncounter]
  └─► If CooldownRemaining > 0 or bZoneExhausted: return
  └─► EncounterState = Active
  └─► ActiveEncounterType = Type
  └─► CalculateIntensity()
  └─► Based on Type:
         Patrol:       Spawn 1-2 patrol enemies, set patrol routes
         Ambush:       All enemies spawn at once, no delay, trigger dialogue
         WaveBased:    TriggerWaveBasedEncounter(Intensity)
         Reinforcement: Spawn 1-3 enemies near existing combat
         Boss:         Spawn single boss enemy, lock area
         Escalation:   Start wave timer, spawn escalating until retreat or all dead
         Environmental: Trigger hazard events instead of enemies
         Scripted:     Execute designer-defined encounter
  └─► Broadcast OnEncounterStarted

[TriggerWaveBasedEncounter]
  └─► CurrentWaveIndex = 0
  └─► For each wave in Waves:
         Wave.DifficultyMultiplier = Get difficulty scale from BPC_DifficultyManager
         Apply difficulty scaling to each enemy class
  └─► SpawnWave(0)

[SpawnWave]
  └─► bWaveInProgress = true
  └─► For each FEncounterSpawnSlot in Waves[WaveIndex].SpawnSlots:
         Delay(SpawnSlot.SpawnDelay)
         SSpawnSingleEnemy(SpawnSlot)
  └─► If Waves[WaveIndex].DialogueTrigger:
         Trigger dialogue via BPC_DialoguePlayback

[SpawnSingleEnemy]
  └─► SpawnLocation = Slot.SpawnLocation
  └─► If Slot.SpawnLocation == ZeroVector:
         SpawnLocation = GetSpawnLocationByMethod(FromLocations or FromNavMesh)
  └─► If not IsSpawnLocationValid(SpawnLocation): return
  └─► Enemy = SpawnActor Deferred(Slot.EnemyClass, SpawnLocation)
  └─► Set difficulty-scaled stats on Enemy:
         Health *= DifficultyManager.HealthMultiplier
         Damage *= DifficultyManager.DamageMultiplier
         Speed *= DifficultyManager.SpeedMultiplier
  └─► If Slot.PatrolRouteIndex >= 0:
         Assign patrol path to enemy
  └─► FinishSpawning(Enemy)
  └─► If Slot.bDropIn:
         Play drop-in animation on Enemy
  └─► If Slot.SpawnEffect:
         UNiagaraFunctionLibrary::SpawnSystemAtLocation
  └─► Bind OnEnemyKilled to Enemy.OnDestroyed
  └─► ActiveEnemies.Add(Enemy)

[OnEnemyKilled]
  └─► ActiveEnemies.Remove(Enemy)
  └─► Add to MetricsTracker for scoring
  └─► If ActiveEnemies.Num() == 0:
         OnAllEnemiesDead()
  └─► If EncounterState == Active and ActiveEncounterType == Escalation:
         CalculateIntensity()
         If should escalate:
              SpawnWave more enemies
         If should de-escalate:
              RetreatEnemies()

[OnAllEnemiesDead]
  └─► If ActiveEncounterType == WaveBased:
         CurrentWaveIndex++
         If CurrentWaveIndex < Waves.Num():
              SpawnWave(CurrentWaveIndex)
         Else:
              EndEncounter()
  └─► Else:
         EndEncounter()

[EndEncounter]
  └─► EncounterState = Completed
  └─► EncounterCount++
  └─► If EncounterCount >= MaxEncountersPerZone:
         ExhaustZone()
  └─► Else:
         StartCooldown(MinCooldown, MaxCooldown)
  └─► Broadcast OnEncounterEnded
  └─► Reward player via BPC_PlayerMetricsTracker

[CalculateIntensity]
  └─► Base intensity from BPC_DifficultyManager.CurrentDifficulty
  └─► Multiply by BPC_FearSystem.CurrentFearLevel factor (0.5 at Calm, 2.0 at Panic)
  └─► Adjust by BPC_AtmosphereController.CurrentState:
         Exploration: *0.5 (fewer enemies)
         Suspense:    *1.0 (standard)
         Combat:      *2.0 (more enemies)
         Panic:       *1.5 (intense but fewer than combat)
  └─► Clamp to EEncounterIntensity range
  └─► Return

[GetSpawnLocationByMethod]
  └─► FromLocations: Pick random from SpawnLocations array
  └─► FromNavMesh: Query UNavigationSystemV1::GetRandomPointInNavigableRadius
         Ensure distance from player >= MinEnemyDistance
  └─► FromVolumes: Random point within EncounterVolumeBox
         Project to nav mesh
  └─► FromPortals: Pre-placed portal actor locations
  └─► FromVent: Vent location list
  └─► CeilingDrop: Above player location + random offset
         Ensure valid nav mesh below

[IsSpawnLocationValid]
  └─► Check distance from player >= MinEnemyDistance
  └─► Line trace from player to spawn location:
         If blocked and distance < 500: location is behind obstacle, valid (ambush)
         If clear and distance < 500: location is visible, valid for patrol
         If distance > 2000: always valid
  └─► Check nav mesh projection is valid
  └─► Check not overlapping existing enemies

Event Dispatchers

Name Payload Description
OnEncounterStarted EncounterType: EEncounterType, Intensity: EEncounterIntensity Encounter began
OnEncounterEnded bPlayerSurvived: Bool, EnemiesKilled: Int32 Encounter finished
OnWaveStarted WaveIndex: Int32, WaveName: FName New wave beginning
OnWaveCompleted WaveIndex: Int32 Wave cleared
OnEnemySpawned Enemy: BP_EnemyBase Individual enemy spawned

Communications With

Target Method Why
BPC_DifficultyManager Direct call Difficulty scaling for encounter
BPC_FearSystem Get owner Fear influence on intensity
BPC_AtmosphereController Get owner Atmosphere alignment
BP_DynamicEvent Cast Encounter as dynamic event
AI_EnemyBase On spawned Set encounter-aware behaviors
BP_EnemyBase On spawned Set difficulty-scaled stats
BPC_PlayerMetricsTracker Event Encounter scoring
BPC_NarrativeState Event Narrative-gated encounters
BPC_DialoguePlayback Event Wave-start dialogue

Reuse Notes

  • Place BPC_ProceduralEncounter on a volume actor or game mode
  • Configure spawn points as child actors or arrays in details panel
  • Encounter exhaustion prevents infinite grinding in one area
  • Difficulty + Fear + Atmosphere combine to produce dynamic intensity
  • Nav mesh spawning ensures enemies always have valid pathfinding
  • Encounter state machine: Ready -> Active -> Cooldown -> Exhausted
  • All encounters work with or without pre-placed spawn locations
  • Each enemy spawned gets difficulty-scaled stats at spawn time