From d7dadd5dea8a320679ab3215db6b54e8bf57eb11 Mon Sep 17 00:00:00 2001 From: admin Date: Tue, 19 May 2026 11:13:11 +0000 Subject: [PATCH] Add Common UE5 Blueprint Implementation Patterns --- ...n-UE5-Blueprint-Implementation-Patterns.md | 295 ++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100644 Common-UE5-Blueprint-Implementation-Patterns.md diff --git a/Common-UE5-Blueprint-Implementation-Patterns.md b/Common-UE5-Blueprint-Implementation-Patterns.md new file mode 100644 index 0000000..9e9273b --- /dev/null +++ b/Common-UE5-Blueprint-Implementation-Patterns.md @@ -0,0 +1,295 @@ +# Common UE5 Blueprint Implementation Patterns + +**Purpose:** This document catalogs the recurring Blueprint implementation patterns used throughout the framework. When implementing a blueprint spec into an actual UE5 Blueprint asset, reference these patterns for consistent, correct implementation. + +--- + +## Pattern 1: Interface-First Communication + +**When to Use:** Any time System A needs to call a function on System B without knowing System B's concrete class. + +**Blueprint Implementation:** +``` +[System A Blueprint] + TargetActor = GetOwner() // or any actor reference + bImplements = DoesImplementInterface(TargetActor, I_Interactable) + Branch(bImplements) + True → Call I_Interactable::ExecuteInteraction(TargetActor, Self) + False → Return / Log Warning +``` + +**Framework Examples:** `BPC_InteractionDetector` → `I_Interactable`, `SS_SaveManager` → `I_Persistable`, Weapons → `I_Damageable` + +**Key Rules:** +- Always check `DoesImplementInterface` before calling +- Never cast to concrete class — use the interface +- Default return values (false/0.0f/empty) handle missing implementations gracefully + +--- + +## Pattern 2: Event Dispatcher Binding (UI Display) + +**When to Use:** Any system that needs to react to state changes in another system. + +**Blueprint Implementation:** +``` +[HUD Widget Blueprint — Event Construct] + PlayerPawn = GetOwningPlayerPawn() + HealthComponent = PlayerPawn.FindComponentByClass(BPC_HealthSystem) + Bind Event to HealthComponent.OnHealthChanged + → Custom Event: OnHealthChangedHandler(OldHealth, NewHealth, Delta) + → ProgressBar.SetPercent(NewHealth / MaxHealth) + +[HUD Widget Blueprint — Event Destruct] + Unbind Event from HealthComponent.OnHealthChanged +``` + +**Framework Examples:** `WBP_HUDController` binds to `OnHealthChanged`, `GS_CoreGameState` binds to `OnGamePhaseChanged` + +**Key Rules:** +- Always unbind in Event Destruct to prevent dangling references +- Never use Event Tick for polling — always bind to dispatchers +- Normalize values (0.0-1.0) before sending to UI for smooth interpolation + +--- + +## Pattern 3: Subsystem Lookup (Global Service Resolution) + +**When to Use:** Any system that needs a global service (save, audio, UI, input). + +**Blueprint Implementation:** +``` +[Any Blueprint] + GameInstance = GetGameInstance() + Cast to GI_GameFramework → Framework + SubsystemRef = Framework.GetSubsystem(Tag) // or FL_GameUtilities.GetSubsystemSafe() + IsValid(SubsystemRef)? + True → Call Subsystem function + False → Log warning, return gracefully +``` + +**Framework Examples:** Any system calling `SS_SaveManager.Save()`, `SS_AudioManager.PlaySound()` + +**Key Rules:** +- Always use `FL_GameUtilities.GetSubsystemSafe()` — returns null instead of crashing +- Check validity of the returned subsystem before calling functions +- Subsystems are singletons — no need to cache, just look up when needed + +--- + +## Pattern 4: Data Asset Configuration + +**When to Use:** Any system that needs configurable data (item stats, weapon balance, encounter rules). + +**Blueprint Implementation:** +``` +[Component Configuration] + Variable: ItemData + Type: DA_ItemData (Object Reference → Primary Data Asset) + Instance Editable: ✓ + Expose on Spawn: ✓ + Category: "Config" + +[Runtime Usage] + ItemData.ItemTag → GameplayTag + ItemData.DisplayName → Text for UI + ItemData.Weight → Float for carry capacity + ItemData.StackLimit → Integer for stack management +``` + +**Framework Examples:** All systems that reference `DA_*` Data Assets + +**Key Rules:** +- Data Assets are read-only at runtime — never modify them +- Use Soft Object References for async loading large Data Asset collections +- Register Data Assets with Primary Asset Manager for streaming support + +--- + +## Pattern 5: Timer-Based Ticks (Not Event Tick) + +**When to Use:** Any repeating operation that doesn't need per-frame precision (regen, decay, scan). + +**Blueprint Implementation:** +``` +[BeginPlay] + Set Timer by Event + Event: RegenTick + Time: 0.1 (seconds) + Looping: ✓ + +[Custom Event: RegenTick] + CurrentStamina = Min(MaxStamina, CurrentStamina + RegenRate * 0.1) + Fire OnStaminaChanged + If CurrentStamina >= MaxStamina: + Clear Timer (RegenTimerHandle) +``` + +**Framework Examples:** `BPC_HealthSystem` regen, `BPC_StaminaSystem` drain, `BPC_StressSystem` decay, `BPC_InteractionDetector` scan + +**Key Rules:** +- Use 0.1s intervals for smooth but performant updates +- Store timer handles and clear them on component destroy +- Never use Event Tick unless absolutely necessary (physics, camera) + +--- + +## Pattern 6: State Machine with Enum Switch + +**When to Use:** Any system that has distinct, mutually exclusive states. + +**Blueprint Implementation:** +``` +[Function: SetState(NewState)] + OldState = CurrentState + Switch on NewState: + Case StateA: + // StateA setup logic + Case StateB: + // StateB setup logic + Case StateC: + // StateC setup logic + CurrentState = NewState + Fire OnStateChanged(OldState, NewState) +``` + +**Framework Examples:** `BP_DoorActor` (Closed/Opening/Open/Closing/Locked/Barricaded), `BP_WeaponBase` (Holstered/Equipping/Ready/Firing/Reloading), `BPC_AIStateMachine` (Patrol/Search/Combat/Flee) + +**Key Rules:** +- Store previous state for transition detection +- Fire dispatcher on every state change +- Block operations that don't make sense in current state + +--- + +## Pattern 7: Validation Before Action + +**When to Use:** Any function that modifies state and can fail. + +**Blueprint Implementation:** +``` +[Function: AddItem(ItemData, Quantity)] + // Validate + FreeSlot = FindFreeSlot() + If FreeSlot < 0: + Fire OnInventoryFull + Return E_InventoryOperationResult::InventoryFull + + OverWeight = CheckWeight(ItemData.Weight * Quantity) + If OverWeight: + Return E_InventoryOperationResult::WeightCapacityExceeded + + // Execute + SetSlot(FreeSlot, ItemData, Quantity) + RecalculateWeight() + Fire OnItemAdded + Return E_InventoryOperationResult::Success +``` + +**Framework Examples:** `BPC_InventorySystem.AddItem`, `BPC_StaminaSystem.DrainStamina`, `BPC_HidingSystem.EnterHideSpot` + +**Key Rules:** +- Validate ALL conditions before making ANY changes +- Return descriptive result codes, not just true/false +- Fire error dispatchers with human-readable failure reasons + +--- + +## Pattern 8: RepNotify for Networked State + +**When to Use:** Any replicated variable that needs local effects when changed remotely. + +**Blueprint Implementation:** +``` +[Variable] + CurrentHealth: Float + Replication: RepNotify + OnRep Function: OnRep_CurrentHealth + +[Function: OnRep_CurrentHealth] + Fire OnHealthChanged (with cached old value) + // This runs on clients when server changes the value + // Local effects (UI update, effects) fire here +``` + +**Framework Examples:** All replicated variables in `GS_CoreGameState`, `BPC_InventorySystem.Slots` + +**Key Rules:** +- RepNotify fires on clients, NOT on server (server handles effects in the setter) +- Cache old value before replication to use in OnRep +- Single-player games can ignore replication entirely — framework is SP-first + +--- + +## Pattern 9: Tag-Driven Filtering + +**When to Use:** Any time you need to filter or categorize (items, interactions, states, narrative). + +**Blueprint Implementation:** +``` +[Function: HasTag(Actor, Tag)] + TagContainer = Actor.GetGameplayTagContainer() // or via interface + Return TagContainer.HasTag(Tag) + +[Function: FindItemsByTag(Tag)] + FilteredArray = [] + For Each Slot in Inventory.Slots: + If Slot.Entry.ItemData.ItemTag.MatchesTag(Tag): + Add to FilteredArray + Return FilteredArray +``` + +**Framework Examples:** Every system — tags replace booleans and strings everywhere + +**Key Rules:** +- Framework tags use `Framework.` prefix; project tags use `Game.` prefix +- All tags documented in `GI_GameTagRegistry` +- Never use `FName` or `FString` for state — always GameplayTags + +--- + +## Pattern 10: Linked Actor Notifications + +**When to Use:** When one actor's state change should trigger other actors (door opens → lights turn on). + +**Blueprint Implementation:** +``` +[Variable: LinkedActors] + Type: Array of Actor + Instance Editable: ✓ + Category: "Connections" + +[On Door Opened] + For Each LinkedActor in LinkedActors: + bImplements = DoesImplementInterface(LinkedActor, I_Toggleable) + If bImplements: + Call I_Toggleable::SetState(LinkedActor, True) +``` + +**Framework Examples:** `BP_DoorActor` notifying lights/traps, `BP_PuzzleDeviceActor` unlocking connected doors + +**Key Rules:** +- Use interfaces (I_Toggleable, I_Adjustable) for linked actor communication +- Designer sets LinkedActors in editor — no code changes needed +- Order of linked actor notification may matter — test edge cases + +--- + +## Quick Reference: Which Pattern for What? + +| Need | Pattern | +|------|---------| +| Call a function on unknown actor type | Pattern 1: Interface-First | +| React to another system's state change | Pattern 2: Dispatcher Binding | +| Access global services (save, audio, UI) | Pattern 3: Subsystem Lookup | +| Configure system behavior without code | Pattern 4: Data Asset | +| Repeating operation at interval | Pattern 5: Timer-Based Tick | +| Manage mutually exclusive states | Pattern 6: State Machine | +| Operation that can fail | Pattern 7: Validation Before Action | +| Network state synchronization | Pattern 8: RepNotify | +| Filter/categorize by type | Pattern 9: Tag-Driven Filtering | +| Chain reactions between actors | Pattern 10: Linked Actor Notifications | + +--- + +*Implementation Patterns v1.0 — Reference when building blueprint specs into UE5 Blueprint assets.*