π§ͺ Debugging & Extension Tips
Overview
This section provides practical guidance on how to debug and expand the Shock Simulation system safely and effectively β whether you're working in C++, Blueprints, or both.
The architecture is modular and scalable but also layered. This means debugging requires you to understand where data flows and where it breaks. Extension must respect ownership, lifecycles, and modular separation of logic.
π General Debugging Workflow
When something doesnβt work (e.g. dots donβt show up, FX doesnβt spawn, diagnosis logic fails), try this top-down approach:
- Is the right diagnosis being triggered?
- Check
SimulationManager::ChangeDiagnosis() -
Use
UE_LOG()to confirmSelectedDiagnosis->GetName() -
Does the diagnosis have the right components?
-
Use breakpoints/logs to confirm:
Indicatorsarray populatedRuntimeBehavioris not nullFXlist is not empty
-
Is the component being spawned?
- Breathing Dots:
UBreathingDotWidget - Niagara FX: via socket positions
-
Temp Labels:
AFloatingTemperatureLabel -
If it's a UI issue:
- Use Blueprint breakpoints in the widget
- Confirm
SetDescription()is called -
Log Widget creation (
UE_LOG()or usePrintString()) -
If itβs a 3D issue:
- Use
DrawDebugSphere()orDrawDebugString()to visualize positions
π§ Logging & Debugging Utilities
C++ Logging
UE_LOG(LogTemp, Warning, TEXT("FX Spawned at: %s"), *SpawnLocation.ToString());
UE_LOG(LogTemp, Display, TEXT("Diagnosis: %s"), *Selected->GetName());
Blueprint Debugging
Use:
- PrintString nodes
- Breakpoints in:
- UBreathingDotWidget
- WBP_TemperatureDisplay
- UCPP_DiagnosisDropDownMenu
π― Tips for Common Problems
| π§ͺ Problem | β Solution |
|---|---|
| Indicators not showing | Socket name typo? Mesh doesn't contain it? Use DoesSocketExist() |
| FX not appearing | Niagara System valid? Socket exists? FX destroyed too early? |
| Widget not displaying | Widget created? Anchor within screen bounds? |
| Temp label not visible | Is display enabled? Core/skin sockets defined? |
| OnEnter() not called | Is SetBehavior() actually set in the builder? |
| Crash on change diagnosis | Null pointer? FX or indicator called before fully built? |
π Extension Tips
π Adding New Behavior Logic
Create a new subclass of UShockBehavior, then plug it into your diagnosis:
class UMyCustomShockBehavior : public UShockBehavior {
virtual void OnEnter() override { ... }
virtual void Tick(float DeltaTime) override { ... }
virtual void OnExit() override { ... }
};
DiagnosisBuilder(this)
.SetBehavior(NewObject<UMyCustomShockBehavior>(this))
.Build();
This allows per-frame logic unique to that diagnosis.
π¬οΈ Add Custom Niagara FX
- Create Niagara FX in Content Browser.
- Add to the builder:
.AddEffect(NS_PulseFX, true, FName("spine_03"))
- FX will automatically:
- Spawn on diagnosis enter
- Be destroyed on diagnosis change
Use FDiagnosisEffect to customize:
FDiagnosisEffect(NS_SweatFX, true, "Forehead");
π Add New Indicator Type
If you want to make a new type of UI indicator (e.g. icon overlay, status chip):
- Create a new UMG widget (e.g.
WBP_AlertIcon) - Make a new data class (e.g.
UCustomShockIndicator) - Extend spawn logic in
SimulationManager: - Use
WidgetComponent->SetWidgetClass() - Set data via Blueprint function call (
SetData())
π§ Advanced Debugging (Runtime Visuals)
Debug Niagara Locations
DrawDebugSphere(GetWorld(), Mesh->GetSocketLocation(SocketName), 10.0f, 12, FColor::Red, false, 5.0f);
Trace Tick Lifecycle
If Tick() in UShockBehavior isnβt being called:
- Check PrimaryComponentTick.bCanEverTick = true
- Ensure you're calling RegisterComponent() on it
- Confirm SimulationManager isnβt manually skipping it
π§ͺ Tools & Shortcuts
| Tool | Use Case |
|---|---|
UE_LOG() |
General C++ debug output |
DrawDebugSphere |
Visualize positions for FX and UI |
| Blueprint Logs | Test data passed to widgets |
| Live Blueprint Debugger | Step through widget lifecycle |
| Output Log | Trace startup and runtime events |
π§± Dev Recommendations
- Centralize all changes inside DiagnosisBuilder to avoid logic leaks.
- Prefer data-driven spawning over hardcoded
if (DiagnosisType == X)checks. - When extending UI, keep logic in widgets and only inject data from C++.
- Clean up all spawned actors and widgets in
ChangeDiagnosis()to avoid state leaks. - Add yourself to the top of each diagnosis file (e.g.,
// Modified by Kristers G. on 2025-06-17)