Blueprint and C++ API
Blueprint nodes
Mass Projectiles (function library)
| Node | Inputs → Output | Description |
|---|---|---|
| Get Projectile Subsystem | World Context → Projectile Subsystem |
The world's projectile subsystem (Game and PIE worlds). |
| Fire Projectiles | World Context, Type Config, Fire Event → int |
Spawn Fire Event.Count projectiles of the type. Returns the number spawned. Registers the type on first use. |
| Clear Projectiles | World Context | Destroy every live projectile. Replicates when called on an authority server. |
| Is Gameplay Damage Impact | Impact Type → bool |
True for Stop and Penetration Enter. |
Projectile Subsystem
| Node | Inputs → Output | Description |
|---|---|---|
| Spawn Projectiles | Type Config, Fire Event → int |
Same as Fire Projectiles, called on the subsystem. |
| Register Type Config | Type Config → int |
Preload a type and return its runtime index (-1 if it lacks Projectile Ballistics). Call at BeginPlay to avoid a first-shot hitch. |
| On Projectile Hit Event | (event dispatcher) → Mass Projectile Hit Event |
Authority-only hits. Bind with Bind Event to On Projectile Hit Event. |
Mass Projectile Fire (component)
| Member | Kind | Description |
|---|---|---|
| Projectile Type | Property (soft reference) | Type asset to fire. |
| Rounds Per Minute | Property | Fire rate for Consume Fire Rounds (default 600). |
| Muzzle Offset | Property | Actor-space offset used by Fire (default 150, 0, 0). |
| Pellets Per Shot | Property | Projectiles per round (default 1). |
| Spread Half Angle Deg | Property | Random cone per projectile (default 0). |
| Fire (Rounds) | Function | From owner location + Muzzle Offset along the control rotation. |
| Fire From (Origin, Direction, Rounds) | Function | Explicit muzzle and direction. |
Consume Fire Rounds (Delta Seconds, Max Rounds This Frame = 32) → int |
Function | Whole rounds owed this frame at Rounds Per Minute. |
| Reset Fire Accumulator | Function | Restart the fire-rate accumulator (call on trigger press). |
Mass Projectile Hit (component)
| Member | Kind | Description |
|---|---|---|
| Owner Hits Only | Property | Forward only hits whose Hit Actor is this component's owner. |
| On Projectile Hit (Hit) | Event dispatcher | Authority-only hit events. |
Structs and enums
Projectile Fire Event (FProjectileFireEvent)
| Field | Type | Default | Description |
|---|---|---|---|
| Origin | Vector | 0 | World spawn point |
| Direction | Vector | +X | Fire direction (normalized internally) |
| Count | int | 1 | Projectiles in this volley |
| Speed | float | 0 | Launch speed (cm/s); ≤ 0 = type's Default Speed |
| Spread Half Angle Deg | float | 0 | Random cone per projectile |
| Random Seed | int | 0 | Deterministic spread/speed seed; 0 = automatic |
Mass Projectile Hit Event (FMassProjectileHitEvent)
See the field table in Hits and Damage.
Projectile Impact Type (EProjectileImpactType)
Stop · Ricochet · Penetration Enter · Penetration Exit
C++
Add the module to your Build.cs:
PublicDependencyModuleNames.AddRange(new string[] { "MassProjectileSubsystem", "MassSpawner" });
(MassSpawner provides UMassEntityConfigAsset.)
Firing
#include "Projectile/ProjectileSubsystem.h"
#include "MassEntityConfigAsset.h"
void AMyTurret::FireVolley(const UMassEntityConfigAsset* Type)
{
UProjectileSubsystem* Projectiles = GetWorld()->GetSubsystem<UProjectileSubsystem>();
if (!Projectiles) return;
FProjectileFireEvent Event;
Event.Origin = Muzzle->GetComponentLocation();
Event.Direction = Muzzle->GetForwardVector();
Event.Count = 12;
Event.SpreadHalfAngleDeg = 2.f;
Projectiles->SpawnProjectiles(Type, Event); // replicates automatically on an authority
}
Native hit listener
OnProjectileHit is a native multicast delegate with the compact worker payload (FProjectileHitPayload). It is authority-only, like the Blueprint event.
void UMyDamageSystem::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
if (UProjectileSubsystem* Projectiles = Collection.InitializeDependency<UProjectileSubsystem>())
{
HitHandle = Projectiles->OnProjectileHit.AddUObject(this, &UMyDamageSystem::HandleHit);
}
}
void UMyDamageSystem::HandleHit(const FProjectileHitPayload& Hit)
{
if (Hit.Event == EProjectileImpactType::Stop || Hit.Event == EProjectileImpactType::PenetrationEnter)
{
// Hit.HitActor, Hit.Location, Hit.Surface, Hit.TypeIndex ...
}
}
OnProjectileHitEvent (dynamic, FMassProjectileHitEvent) carries the same hits with Damage and Type Config resolved. Prefer it when you want Base Damage.
OnProjectileHitLocal has the same signature but fires on every machine, clients included, each with its own locally simulated copy of the hit. Use it for cosmetic reactions only (hit markers, UI, local effects), never for damage or scoring.
Useful subsystem calls
| Function | Description |
|---|---|
SpawnProjectiles(TypeConfig, FireEvent) |
Spawn; returns the count spawned |
RegisterTypeConfig(TypeConfig) |
Preload a type; returns its runtime index |
RequestClearAll() |
Clear all projectiles (replicates from an authority) |
GetStats() |
FStats snapshot: Active, Traces, Hits, TracersDrawn, timings |
SetWindVelocity(FVector) / GetWindVelocity() |
Manual wind (cm/s) |
SetVisualizer(IProjectileVisualizer*) |
Replace the renderer (see below) |
Custom visualizer (C++)
The core module has no Niagara dependency. To draw projectiles another way (instanced meshes, a custom Niagara layout, a debug renderer):
- Implement
IProjectileVisualizer(Projectile/ProjectileVisualizer.h):
| Method | Called |
|---|---|
Prewarm() |
World init, BeginPlay, and each cosmetic frame (idempotent) |
ResetAssetCache() |
proj.ReloadAssets |
CanDrawImpacts() |
Return false to use the cheap per-type fallback puff |
DrawImpacts(TConstArrayView<FProjectileImpactFXEvent>) |
Every cosmetic frame, even when empty |
DrawTracers(TypeIndex, const FProjectileTypeViz&) |
Per type, each frame (Positions / Velocities within the tracer budget) |
DrawSmoke(TConstArrayView<FProjectileSmokeSample>) |
Every cosmetic frame, even when empty |
- Register it from a
UWorldSubsystem::Initialize(before worldPostInitialize):
Collection.InitializeDependency<UProjectileSubsystem>()->SetVisualizer(&MyVisualizer);
- Turn off Project Settings → Mass Projectile Niagara → Enable Niagara Visualizer.
All visualizer methods run on the game thread, and only where a local viewer exists (never on dedicated servers).