Decals and hit reactions

Non-breaking hit reactions with bounded optional impulse, and deterministic impact decals with a per-object limit.

Both features are opt-in and disabled by default. They cover the hits that do not destroy an object — the majority of hits in a melee-heavy game.

Hit reactions

A hit reaction is a request emitted for a valid hit that leaves the object standing.

PropertyDefaultMeaning
bEnableHitReactionsfalseMaster switch
MinimumHitReactionPowerVeryLightPower gate for reactions
bApplyBuiltInPhysicsReactiontrueApply a bounded impulse when the intact component already simulates physics
HitReactionImpulseMultiplier0.2Fraction of the incoming impulse used
MaximumHitReactionImpulse250.0Hard cap on the applied impulse

When the impulse applies

The impulse never turns simulation on

The built-in impulse is applied only when the intact primitive component is simulating physics at that moment. A hit reaction never switches simulation on by itself.

Whether the intact simulates is decided by its physics mode, at BeginPlay:

  • New generations use Simulated by default, so their intact prop is already simulating and the built-in impulse can move it;
  • Static, Keep Existing and older setups that were not migrated are not changed silently — a static prop stays static, and the impulse is skipped.

See Intact physics and fall damage.

The request is emitted either way. An object that does not simulate physics still reports the reaction, so your own code can play an animation, a shader wobble or a sound instead.

The request payload

FSDFHitReactionRequest:

FieldMeaning
SourceActorThe object that was hit
LocationWorld-space impact position
DirectionDirection of the incoming hit
RequestedImpulseImpulse the profile computed, after multiplier and cap
DestructionPowerPower of the causing hit
RandomSeedSeed for deterministic reaction selection
bPhysicsImpulseAppliedWhether the built-in impulse was actually applied

Listen on OnHitReactionRequested, or read GetLastHitReactionRequest on demand.

bPhysicsImpulseApplied tells you unambiguously whether the object moved because of SDF, which is what your own reaction logic needs in order not to double up.

Typical use

  • A hanging lantern that swings when struck — physics simulating, built-in impulse enabled.
  • A stone statue that flashes and sparks but does not move — reactions enabled, Physics Static.
  • A crate that only reacts to real attacks — raise MinimumHitReactionPower above the value your light attacks carry.

Impact decals

PropertyDefaultMeaning
bEnableImpactDecalsfalseMaster switch
bEnableBuiltInDecalSpawningtrueDisable when an external listener owns decal presentation
MinimumDecalPowerVeryLightPower gate
MaximumImpactDecals3Per-object limit (0–32)
ImpactDecalsemptyWeighted variations

Decal variations

FSDFWeightedDecal:

PropertyDefaultMeaning
MaterialnoneSoft UMaterialInterface reference
Weight1.0Relative selection weight
Size(8, 16, 16)Decal projection box
LifeSpan20.0Seconds before the decal fades out
FadeScreenSize0.01Screen size below which the decal stops rendering
bRandomizeRolltrueRandomise roll around the projection axis

Deterministic orientation

SelectWeightedDecalVariation(Variations, RandomSeed, ImpactNormal, OutRotation) picks the variation and computes the rotation. Decals are projected along the impact normal; with bRandomizeRoll enabled the roll is derived from the seed, so repeated hits do not produce visibly identical stamps — and the same seed reproduces the same stamp exactly.

The per-object limit

MaximumImpactDecals caps how many decals one object carries. Once the limit is reached, further decal requests are still emitted but marked bSuppressedByObjectLimit, so an external system knows the framework deliberately declined rather than failed.

GetActiveImpactDecalCount returns the current count. Tracked decals are destroyed when the object is cleaned up, so a destroyed crate does not leave its dents floating in the level.

The request payload

FSDFDecalRequest:

FieldMeaning
SourceActorThe object that was hit
LocationWorld-space impact position
ImpactNormalProjection normal
RotationResolved rotation
SizeResolved projection size
SelectedMaterialThe variation picked
RandomSeedSeed used
SelectedVariationIndexIndex into the profile array
bBuiltInSpawnRequestedBuilt-in spawning was configured
bBuiltInSpawnAttemptedA spawn was attempted
bBuiltInSpawnSucceededThe decal component was created
bSuppressedByObjectLimitThe per-object limit declined this request

Listen on OnImpactDecalRequested, or read GetLastImpactDecalRequest.

Cost guidance

Decals are cheap individually and expensive in aggregate. In a room with thirty destructible props, a limit of 3 per object is already up to ninety decal components. Two practical rules:

  • keep MaximumImpactDecals at 1 or 2 for common props, and reserve 3+ for hero objects;
  • keep LifeSpan short — a decal that outlives the fight adds cost without adding information.

Last updated: 2026-09-15

Type to search titles, sections and keywords.