π₯ FX and Materials
Overview
The FX system handles all visual feedback for shock symptoms β such as: - Sweating - Pale or discolored skin - Pulse bursts - Heat wave distortions - Blood particle suppression or restart
Each FX component is spawned dynamically based on the selected diagnosis, and cleared automatically when the diagnosis changes. FX can be easily extended, reused, and targeted to specific anatomical regions using sockets.
π§± System Architecture
FX are defined in FDiagnosisEffect
Each diagnosis can contain multiple effects:
TArray<FDiagnosisEffect> Effects;
Each FDiagnosisEffect holds:
- UNiagaraSystem* NiagaraEffect β The FX to spawn
- bool bAutoDestroy β Should it clean up automatically
- FName TargetSocket β Where on the mesh it attaches
These effects are added using the diagnosis builder:
.AddEffect(NS_SweatFX, true, FName("Forehead"))
Niagara FX Spawn Logic
All effects are spawned inside:
UCPP_SimulationManager::ChangeDiagnosis()
- Previous Niagara FX actors are destroyed.
- New FX are retrieved from the
Effectsarray of the diagnosis. - For each FX:
- The mesh socket location is calculated.
- A
UNiagaraComponentis spawned at that location. - The Niagara system is assigned and activated.
Stored components are cached for cleanup:
TArray<UNiagaraComponent*> SpawnedFX;
π¨ Custom Materials for Symptoms
Some shock types use material parameter collections or dynamic material instances to drive visual feedback, such as: - Skin pallor or flushing - Temperature shimmer - Dehydration effects
To use: 1. Create a Material Parameter Collection (MPC) in Unreal. 2. Set it via C++ using:
UMaterialParameterCollectionInstance* MPC = GetWorld()->GetParameterCollectionInstance(MyCollection);
MPC->SetScalarParameterValue(FName("SkinPaleness"), 0.6f);
- Connect that parameter to your material nodes (e.g.
Base Color,Opacity).
Optional: Blend two skin materials using a parameter curve or diagnosis duration.
π§ Example Setup in DiagnosisBuilder
DiagnosisBuilder(this)
.SetName("Distributive Shock")
.AddEffect(NS_SweatFX, true, FName("Forehead"))
.AddEffect(NS_PulseFX, true, FName("Wrist"))
.Build();
π§ͺ Debugging FX
Verify Spawned Locations
Use debug helpers to confirm socket positions:
DrawDebugSphere(GetWorld(), SkeletalMesh->GetSocketLocation(SocketName), 10.0f, 12, FColor::Blue, false, 5.0f);
Check FX Reference
- Is the
UNiagaraSystem*asset valid in the builder? - Has it been deleted or renamed?
- Try logging FX names:
UE_LOG(LogTemp, Warning, TEXT("Spawning FX: %s"), *FX.NiagaraEffect->GetName());
Confirm Niagara Activation
- Check that
NiagaraComponent->Activate(true)is being called - Set looping duration inside the Niagara System if needed
- Add Niagara debug components to your level (optional)
π Performance Considerations
| Concern | Strategy |
|---|---|
| Too many FX spawning | Pool Niagara components instead of respawning each time |
| FX doesnβt clean up | Use bAutoDestroy = true OR manually call DestroyComponent() |
| Material blending slow | Use shader LODs or pre-baked materials for critical systems |
π Tips for Adding New Effects
- Design your Niagara effect in the Content Browser
- Add it to a diagnosis with:
.AddEffect(NS_CustomFX, true, FName("spine_03")) - Confirm socket exists on the anatomical mesh
- Use short looping FX unless the diagnosis has
Tick()logic that modifies it over time
Optional: Wrap logic inside UShockBehavior::OnEnter() or Tick() to enable time-based parameter changes.
π§© Advanced FX Ideas
- Sweat FX that becomes heavier based on blood loss
- Temperature shimmer that increases with fever
- Pulsing FX synchronized with heart rate
- Color overlays based on simulated oxygen saturation
- Localized particle FX only for left arm/right leg/etc.
Combine these with indicator logic or runtime simulation parameters to create layered effects.