$npx -y skills add quodsoler/unreal-engine-skills --skill ue-niagara-effectsUse this skill when working with Niagara particle systems, VFX, effects, emitter, Niagara component, or Niagara parameter in Unreal Engine C++. Covers spawning systems, setting parameters, data interfaces (SkeletalMesh, StaticMesh, Curve, Array), OnSystemFinished delegate, and pe
| 1 | # UE Niagara Effects |
| 2 | |
| 3 | You are an expert in controlling Unreal Engine's Niagara VFX system from C++. |
| 4 | |
| 5 | ## Context Check |
| 6 | |
| 7 | Read `.agents/ue-project-context.md` before proceeding. Confirm: |
| 8 | |
| 9 | - The `Niagara` plugin is listed under enabled plugins (`Plugins/FX/Niagara`). |
| 10 | - The target module's `Build.cs` has `"Niagara"` (and optionally `"NiagaraCore"`) in `PublicDependencyModuleNames`. |
| 11 | - Platform targets: note whether mobile or dedicated-server builds are in scope, because Niagara is |
| 12 | typically suppressed on dedicated servers and may need LOD simplification on mobile. |
| 13 | |
| 14 | ## Information Gathering |
| 15 | |
| 16 | Before writing Niagara C++ code, clarify: |
| 17 | |
| 18 | 1. **Effect lifecycle** — one-shot (fire and forget) or persistent / looping? |
| 19 | 2. **Parameter needs** — which Niagara User Parameters must be set from gameplay (positions, colors, scalars)? |
| 20 | 3. **Data interfaces required** — SkeletalMesh, StaticMesh, Curve, Array, or custom? |
| 21 | 4. **Simulation target** — CPU or GPU sim? (affects which DI features are available) |
| 22 | 5. **Performance budget** — pooling required? Mobile scalability tier? |
| 23 | 6. **Completion handling** — does gameplay need a callback when the effect finishes? |
| 24 | |
| 25 | --- |
| 26 | |
| 27 | ## System Structure (UE Concept Map) |
| 28 | |
| 29 | ``` |
| 30 | UNiagaraSystem (asset: UNiagaraSystem) |
| 31 | └── UNiagaraEmitter[] (per-emitter asset, referenced via FNiagaraEmitterHandle) |
| 32 | └── UNiagaraScript[] (Spawn / Update / Event scripts; authored in Niagara editor) |
| 33 | └── Modules (stack of NiagaraScript nodes; not C++ classes) |
| 34 | |
| 35 | Runtime instances: |
| 36 | UNiagaraComponent (scene component that drives one UNiagaraSystem instance) |
| 37 | └── FNiagaraSystemInstance (internal runtime state; access via GetSystemInstanceController()) |
| 38 | ``` |
| 39 | |
| 40 | **Key rule**: authors expose parameters to C++ by setting their namespace to `User.` in the Niagara |
| 41 | editor. Only `User.*` parameters can be overridden at runtime from C++. |
| 42 | |
| 43 | --- |
| 44 | |
| 45 | ## Spawning Niagara Systems |
| 46 | |
| 47 | ### Fire-and-Forget (One-Shot) at World Location |
| 48 | |
| 49 | ```cpp |
| 50 | #include "NiagaraFunctionLibrary.h" |
| 51 | #include "NiagaraComponent.h" |
| 52 | |
| 53 | // Minimal one-shot spawn — component auto-destroys when the system completes. |
| 54 | UNiagaraComponent* NiagaraComp = UNiagaraFunctionLibrary::SpawnSystemAtLocation( |
| 55 | this, // WorldContextObject |
| 56 | ImpactVFXSystem, // UPROPERTY(EditAnywhere) UNiagaraSystem* |
| 57 | HitLocation, // FVector Location |
| 58 | FRotator::ZeroRotator, // FRotator Rotation |
| 59 | FVector(1.f), // FVector Scale |
| 60 | /*bAutoDestroy=*/ true, |
| 61 | /*bAutoActivate=*/ true, |
| 62 | /*PoolingMethod=*/ ENCPoolMethod::AutoRelease, // use pool when available |
| 63 | /*bPreCullCheck=*/ true |
| 64 | ); |
| 65 | |
| 66 | // Set parameters before the first tick if needed. |
| 67 | if (NiagaraComp) |
| 68 | { |
| 69 | NiagaraComp->SetVariableVec3(FName("User.HitNormal"), HitNormal); |
| 70 | NiagaraComp->SetVariableLinearColor(FName("User.HitColor"), DamageColor); |
| 71 | } |
| 72 | ``` |
| 73 | |
| 74 | ### Attached to a Component (Persistent / Looping) |
| 75 | |
| 76 | ```cpp |
| 77 | // Attaches to a socket and stays active until manually deactivated. |
| 78 | UNiagaraComponent* TrailComp = UNiagaraFunctionLibrary::SpawnSystemAttached( |
| 79 | TrailVFXSystem, |
| 80 | WeaponMesh, // USceneComponent* AttachToComponent |
| 81 | FName("MuzzleSocket"), // FName AttachPointName |
| 82 | FVector::ZeroVector, |
| 83 | FRotator::ZeroRotator, |
| 84 | EAttachLocation::SnapToTarget, |
| 85 | /*bAutoDestroy=*/ false, |
| 86 | /*bAutoActivate=*/ true, |
| 87 | ENCPoolMethod::ManualRelease, |
| 88 | /*bPreCullCheck=*/ true |
| 89 | ); |
| 90 | ``` |
| 91 | |
| 92 | ### Persistent Component on an Actor (Preferred for Repeated Use) |
| 93 | |
| 94 | ```cpp |
| 95 | // In header: |
| 96 | UPROPERTY(VisibleAnywhere) |
| 97 | TObjectPtr<UNiagaraComponent> EngineTrailVFX; |
| 98 | |
| 99 | // In constructor: |
| 100 | EngineTrailVFX = CreateDefaultSubobject<UNiagaraComponent>(TEXT("EngineTrailVFX")); |
| 101 | EngineTrailVFX->SetupAttachment(GetRootComponent()); |
| 102 | EngineTrailVFX->SetAutoActivate(false); // start inactive; activate via gameplay |
| 103 | |
| 104 | // In gameplay code: |
| 105 | EngineTrailVFX->SetAsset(EngineTrailSystem); // swap asset without destroying component |
| 106 | EngineTrailVFX->Activate(/*bReset=*/ true); |
| 107 | ``` |
| 108 | |
| 109 | ### Lifecycle Control |
| 110 | |
| 111 | ```cpp |
| 112 | NiagaraComp->Activate(/*bReset=*/ false); // activate; resume if paused |
| 113 | NiagaraComp->Activate(/*bReset=*/ true); // activate with full reset |
| 114 | NiagaraComp->Deactivate(); // stop spawning, let particles drain |
| 115 | NiagaraComp->DeactivateImmediate(); // kill all particles immediately |
| 116 | NiagaraComp->ResetSystem(); |