Skip to main content

Core Concepts

This page explains how ElysImpact’s pipeline works end-to-end, from calling PlayResponse to each handler completing.

The Pipeline

PlayResponse(Asset, Context)


UERP_ImpactSubsystem::CreateSession

├─ Channel filter (muted? → drop)
├─ Feel Profile suppression check
├─ Combined intensity computation
│ ContextOverride × AssetMultiplier × GlobalScale × ChannelScale × DI curve
├─ Choreography role assignment
├─ Dramatic Intensity accumulation


UERP_ImpactSession::Start

└─ For each Handler (concurrent):
├─ Pre-conditions (enabled? ExecutionChance? distance? tags?)
├─ StartDelay timer
└─ Handler::Play_Internal

Response Assets

UERP_ImpactResponseAsset is a UDataAsset. Open it in the editor to configure:

PropertyDescription
HandlersList of inline handlers (EditInlineNew — configured directly in the asset)
IntensityMultiplierScales the combined intensity for all handlers in this asset
ChannelsGameplayTag set — used for muting and per-channel intensity
DramaticContributionHow much this response contributes to the target’s DI accumulator
ChoreographyGroupTag-based area-response role system (see Choreography below)

Creating a Response Asset

  1. Content Browser → right-click → Miscellaneous → Data Asset → UERP_ImpactResponseAsset
  2. Add handlers via the + button in the Handlers array
  3. Expand each handler to configure its properties

Handlers

A handler is an EditInlineNew UObject that performs exactly one effect. Handlers run concurrently within a session — a Camera Shake and a Sound Effect in the same asset both start at the same time (subject to their individual StartDelay).

Common Handler Properties

All handlers share these base properties (on the UERP_ImpactHandler base class):

PropertyDescription
bEnabledToggle without removing the handler
ExecutionChanceProbability [0..1] that this handler fires on any given play
StartDelaySeconds to wait before playing (within the session)
IntensityScalePer-handler intensity multiplier
IntensityRandomRangeAdds random [-Range, +Range] to final intensity
IntensityOverLifetimeOptional curve: scales intensity over the handler’s duration
MaxPlayDistanceBeyond this distance from the camera, the handler is silenced
LODDistanceFadeDistance at which intensity starts fading
TargetTagRequirementHandler only fires if target has these GameplayTags
SourceTagRequirementHandler only fires if source has these GameplayTags
bQuantizeToBeatDefers play to the next ElysMusicEngine beat division
BeatDivisionWhich beat division to quantize to

Session Isolation

When a session is created, each handler template from the asset is duplicated (DuplicateObject) so concurrent sessions never share mutable state. You can play the same asset on 10 actors simultaneously — each gets its own handler instances.


Intensity

The final intensity passed to each handler is:

CombinedIntensity = Context.IntensityOverride
× Asset.IntensityMultiplier
× Subsystem.GlobalIntensity
× ChannelIntensity (lowest among asset’s channels)
× DICurve(NormalizedDI)
× FeelProfile.GlobalIntensityScale

After choreography role assignment:

  • Secondary role: × ChoreographyGroup.SecondaryIntensityScale
  • Tertiary role: × ChoreographyGroup.TertiaryIntensityScale

Each handler then applies its own IntensityScale and curve on top.


Impact Context

FERP_ImpactContext carries rich event data through the pipeline:

FieldTypeDescription
TargetTWeakObjectPtr<AActor>Actor receiving the response (required)
SourceTWeakObjectPtr<AActor>Actor triggering the response (optional)
InstigatorTWeakObjectPtr<AController>Controller responsible (optional)
EventTagFGameplayTagSemantic label (e.g., Impact.Hit.Heavy)
MagnitudefloatRaw value (damage, force…) — affects DI accumulation
ImpactPointFVectorWorld position of the impact
ImpactNormalFVectorSurface normal at impact
IntensityOverridefloatPer-call intensity multiplier (default 1.0)
bSkipReplicationboolIf true, skip network propagation

Build a context manually or use the helper functions:

// Minimal
FERP_ImpactContext Context = UERP_ImpactStatics::MakeImpactContext(TargetActor, 1.f);

// From a hit result
FERP_ImpactContext Context = UERP_ImpactStatics::MakeImpactContextFromHit(HitResult, Damage);

Dramatic Intensity

The DI system makes repeated responses feel progressively more impactful:

  1. Each PlayResponse call accumulates DI on the target actor: CurrentDI += Magnitude × Asset.DramaticContribution
  2. DI decays over time (exponential decay driven by DecayRate)
  3. Normalized DI [0..1] is fed through the Feel Profile’s DramaticIntensityCurve
  4. The curve output multiplies the combined intensity

Default behavior (no Feel Profile): linear scale from at DI=0 to at DI=1.

Read and reset DI from Blueprint:

Get Dramatic Intensity → (WorldContext, Actor) → float [0..1]
Reset Dramatic Intensity → (WorldContext, Actor)

Choreography

When many actors are hit simultaneously, Choreography prevents visual overload by assigning roles:

  • Primary: Full intensity — the most important response (usually the player’s target)
  • Secondary: Reduced intensity (SecondaryIntensityScale, default 0.6)
  • Tertiary: Minimal intensity (TertiaryIntensityScale, default 0.3)

Configure on the Response Asset’s ChoreographyGroup:

PropertyDescription
GroupTagUnique tag identifying this choreography group
PrimaryLockDurationSeconds before another actor can claim the Primary role
MaxSecondaryCountMax concurrent Secondary responses
SecondaryIntensityScaleIntensity multiplier for Secondary
TertiaryIntensityScaleIntensity multiplier for Tertiary

Set the same GroupTag on all response assets that should compete for roles within an area.


Sessions

A UERP_ImpactSession is a UObject that:

  • Owns the duplicated handler instances
  • Tracks handler completion
  • Fires OnComplete when all handlers finish
  • Is removed from ActiveSessions on the next subsystem tick

Sessions are GC-managed — they live as long as the subsystem holds a reference. You rarely need to interact with sessions directly.

To stop a session early:

UERP_ImpactStatics::StopSession(this, Session);
UERP_ImpactStatics::StopAllOnActor(this, TargetActor);

Next Steps

Browse Handler Reference for all available effects.

Configure intensity scaling in Feel Profiles.

Organize your responses with Channels.