Melee Trace

Documentation Unreal Engine AI Melee Combat

Frame-rate independent swept weapon traces with per-window damage configs and ISECDamageable integration.


Each active frame, USECMeleeTraceComponent sweeps from the last socket positions to the current ones. Fast swings still register hits at 30 or 144 FPS.
Viewport
Interpolation OFF
LVL_SEC_Showcase>Melee Trace
Swing Speed60°
SIM_FPS: 10
STATUS: TUNNELING
0
Successful Hits
Without Interpolation: The fast sword swings 'teleport' over the target between frames, causing a miss.

When to Use This

  • Melee on AI or player pawns.
  • Swings that outrun per-frame overlap checks.
  • Several hit zones on one weapon (blade, pommel).
  • Different damage per montage window through SECDamageConfig.
AEnemyCharacterBase ships with USECMeleeTraceComponent. Add SEC Melee Trace to any other pawn you want in the pipeline.

How It Works

Register trace sockets on the wielder (usually when the weapon equips). StartTracing captures socket positions and enables tick. Each tick sub-steps between previous and current transforms and sweeps sphere, capsule, or two-point capsule shapes (SubStepDistance, MaxSubSteps).
ShapeUse
SphereFists, small contact points.
CapsuleWidens one contact point's swept path. Lies along the sweep, not along the bone.
CapsuleTwoPointSpan between two mesh sockets (typical sword blade).
The first tick after StartTracing records positions only; the trace sweeps from the tick after that, once it holds a previous sample.
Hit order:
  1. TeamFilter and the owner check drop the contacts this swing has no business with.
  2. Classify Contact reads what the contact is: a body to damage, a sensor to report, or something to drop.
  3. Duplicate checks (CanHitActor). One frame lands one hit per target, however many sub-steps the sweep took.
  4. The trace sorts the hit into a target, a downed combatant, or the level.
  5. OnMeleeHit with FSECMeleeHitData, carrying that sorting (contact VFX/SFX hook).
  6. On a target: BuildDamageInfo → damage → Hit EffectsHandleDamageResultOnMeleeHitResponse. A downed combatant or the level takes no damage and reports an empty result.
Damage Application picks how step 6 sends damage. Damageable Interface is the default: it asks the target through ISECDamageable and falls back to Unreal's point damage for a target without it. Point Damage skips the interface. None reports the hit and applies nothing, for a project that drives damage itself from On Melee Hit.
On a machine that is not detecting hits, StartTracing and the tick return early. The authority detects hits unless a subclass overrides ShouldDetectHits. StopTracing clears active sockets, hit records, and disables tick.

What a hit landed on

Each kind decides what the hit costs the swing, and each hit effect picks which kinds it plays on.
KindWhat it isDamageThe swing
DamageableA live target.Sent.Spent on it.
InertA combatant taking nothing right now: a corpse, or a target inside an invulnerability window.None.Spent, and reachable again the moment the target starts taking hits.
SceneryThe level: a wall, a floor, a prop out of combat.None.Held for the whole window, so a wall costs one clang.
Two switches decide the sorting. Respect Can Be Damaged is on by default: an actor with that engine flag switched off takes nothing, so switching it off on death is all a corpse needs to go quiet. Require Damageable Target puts anything without ISECDamageable out of combat, for a project whose weapons should land nothing on props. Leave it off and a breakable crate wired through Any Damage keeps taking hits.
A hit effect carries Run On Damageable Hits, Run On Inert Hits and Run On Scenery Hits. The first is on by default and the other two off, so a corpse and a wall stay silent until you give them an effect of their own. Give that effect a Surface Set and stone, wood and flesh each sound like themselves.

Colliders the swing reports instead of hitting

A collider can sit in front of a character without taking the swings that cross it: a parry box, a volume that wakes something up, a hitbox your own code counts. Tag that collider's component, then list the tag under Sense Component Tags on the trace component. A swing crossing it fires On Melee Sensed carrying the struck component, spends nothing, and reaches the body behind it in the same frame, so the volume costs the character none of its hits. Each sensor reports once per trace window however many frames the swing spends inside it.
Set a sensor collider's response to the trace channel to Overlap. On Block the sweep stops at the sensor and never reaches the body behind it. The Output Log warns and names the component when that happens.
Leave Sense Component Tags empty and every contact counts as a body.

Setup

1. Component on the wielder

Details
SEC Melee Trace Component (SECMeleeTraceComponent)
Damage
Default Damage Config
None
Base Damage
10
Damage Type Class
None
Hit Reset Interval
0
Team Filter
No Filter
SEC | Melee Trace | Damage
Skip Record Tags
0 tags
Sense Component Tags
0 Array elements
Damage Application
Damageable Interface
Respect Can Be Damaged
Require Damageable Target
Trace
Trace Filter
Mode
Channel
Trace Channel
Pawn
Sub Step Distance
10
Max Sub Steps
20
Debug
Draw Debug
Debug Draw Duration
0.1
Default component on the enemy pawn. Add SEC Melee Trace to other wielders manually.
Set Default Damage Config or Base Damage when a notify omits damage.

2. Weapon mesh sockets

Add sockets on the weapon mesh (example: blade_start, blade_end).

3. Sockets on the weapon

A weapon carries its own socket list and registers it on the wielder when equipped, so the trace component sweeps from the blade of whatever the enemy is holding. Releasing the weapon takes those sockets away again.
Weapons covers building the weapon Blueprint and getting it into the enemy's hand. Come back here for the sweep itself.
An unarmed pawn skips the weapon and registers its sockets directly, through RegisterSphereSocket on hand bones.
Per-attack damage comes from the montage notify or component default, not the weapon actor.

4. Damage config

Create SECDamageConfig, assign on the notify or Default Damage Config:
Details
SEC Damage Config (SECDamageConfig)
Damage
Damage
10
Damage Type
None
Damage Type Class
None
Damage Tags
0 tags
Multi Hit Interval
-1
Use Authored Hit Direction
Hit Effects
Hit Effects
0 Array elements
Data asset assigned on the montage notify or the trace component Default Damage Config.
Six configs ship under Core/Damage, one per damage type, each carrying its type tag and a starting damage value. Assign one to get a weapon swinging, then tune the number or branch off your own.
Damage Type names the kind of damage so a target can resist or react by type. The shipped vocabulary splits by what the damage is rather than how it arrived: SEC.Damage.Physical.Slashing, .Piercing and .Bludgeoning, then SEC.Damage.Elemental.Fire, .Ice and .Lightning. Because tags match down the tree, armor can check SEC.Damage.Physical and a ward SEC.Damage.Elemental without naming each type.
Per window: notify Damage ConfigDefault Damage ConfigBase Damage. StartTracingSimple accepts a numeric override; values below zero fall back to Base Damage.
Hit Effects on the config are what a landed hit does beyond the number. SEC Play Gameplay Cues fires impact and target cues, SEC Apply Physics Impulse shoves the struck body along the blow, and subclassing SEC Hit Effect in Blueprint covers anything else. Each effect can sit out a hit through Suppress On Result Tags, Require Damage Applied, or the kind of hit it landed on, so a blocked hit need not shake the screen.
SEC Damage Statics opens the same pipeline to a projectile, an explosion or a hazard: Deal Damage asks the target and falls back to point damage, Deal Point Damage skips the interface, Classify Damage Target sorts a hit the way the sweep does, and Run Hit Effects runs a config's whole effect list once you know the outcome.
A cue fired this way receives the impact point, the impact normal, the struck surface, the damage that landed, a fatal flag, and whatever the target reported in its result tags. One notify can read those tags and branch a parried or blocked hit, which saves authoring a separate cue for each outcome. The plugin registers its own cue folder, so you add no path of your own, and your cues under /Game keep working alongside the shipped ones.

5. Montage window

Add Notify State → SEC Melee Trace Window on strike frames:
Details
SEC Melee Trace Window (SECMeleeTraceNotifyState)
Melee Trace
Socket IDs
1 Array element
Damage Config
DA_SwordDamage
Debug
Enable Debug Draw
Anim notify state on strike frames. Empty Socket IDs activates every registered socket.
Empty Socket IDs activates every registered socket. Names must match each trace socket ID.
Animation montage with SEC Melee Trace Window notify state
Equip, play the montage: register on equip, StartTracing at notify begin, StopTracing at notify end.

Integration

SystemLink
WeaponsBuilding the weapon, its socket list, and arming the enemy so those sockets register.
Reaction SystemHandle Incoming Damage returns ResultTags for reaction selection.
Animation IntegrationMontage windows hold defense tags; SkipRecordTags decides whether a dodge costs the swing.
MultiplayerTrace and damage on the detecting machine, the authority by default; clients follow replicated state.
Configuration ReferenceShared project tuning (reconcile damage fields with this page).
TeamFilter on the trace component (damage gating, not combat target selection):
Details
SEC Melee Trace Component (SECMeleeTraceComponent)
Damage
Team Filter
No Filter
Damage category on the wielder trace component. Filters who can be hit, separate from combat target selection.

AdvancedDelegates and manual control
void StartTracing(const TArray<FName>& SocketIDs, USECDamageConfig* DamageConfig = nullptr, bool bDebugOverride = false);
void StartTracingSimple(const TArray<FName>& SocketIDs, float DamageOverride);
void StopTracing();
 
void RegisterTraceSocket_Struct(const FSECTraceSocket& TraceSocket);
void UnregisterTraceSocket(FName ID);
void UnregisterAllSockets();  // clears every socket, whatever registered it
 
TArray<FName> GetRegisteredSocketIDs() const;
void AddTraceIgnoredActor(AActor* Actor);     // a mount or companion this weapon should pass through
void RemoveTraceIgnoredActor(AActor* Actor);
TArray<AActor*> GetTraceIgnoredActors() const;
OnMeleeHit: FSECMeleeHitData (HitResult, FromSocketID, DamageConfig, Classification).
OnMeleeHitResponse: FSECMeleeHitData + FSECDamageResult.
OnMeleeSensed: FSECMeleeHitData for a sensor the swing crossed, its HitResult naming which collider it was. TeamFilter runs ahead of the sorting, so a sensor on an actor the filter dropped reports nothing.
Override BuildDamageInfo, HandleDamageResult, ClassifyHit or ClassifyContact in a Blueprint or C++ subclass, for crit scaling, pierce, or a sorting rule of your own. BuildDamageInfo receives the socket that struck, so an override can vary damage by contact point. ClassifyContact answers Damage to send the contact through the pipeline, Sense to report it through OnMeleeSensed and leave the swing live, or Ignore to drop it; the default matches the struck component's tags against Sense Component Tags, and an override can read the actor instead.
Blueprint helpers: RegisterSphereSocket, RegisterCapsuleSocket, RegisterTwoPointCapsule.
AdvancedISECDamageable pipeline
FSECDamageInfo: Instigator, DamageCauser (the weapon when the socket sits on one, the wielder otherwise), HitResult, HitDirection, DamageDefinition (ToDamageDefinition() when a config is active), DamageTags, and DamageConfig, the config the window opened with. Subclass SECDamageConfig, add a stagger tier or anything else the attack should carry, then cast DamageConfig inside HandleIncomingDamage to read it. A pool an attack drains, such as poise, belongs in the config's AdditionalVitalDamage rows instead, and GetConfigVitalDamage reads one row back out by tag.
HitDirection is the bearing from attacker to target. IsHitDirectionWithinArc and GetHitDirectionQuadrant measure a guard or a directional reaction against it. The weapon's own path stays on the hit result. Tick Use Authored Hit Direction on the config to send a fixed direction instead, so an uppercut launches upward whatever the geometry said; the physics impulse follows the same value.
FSECDamageResult: DamageApplied (the amount that landed), bWasFatal, ResultTags. A target reached through point damage reports what its Take Damage returned, with no fatal flag and no result tags, since Unreal's path carries neither back.
HandleDamageResult recording:
ResultRecording
Tags match SkipRecordTagsNo record. The trace did not spend the swing, so it lands again on a later frame, which is what a dodge wants.
Anything else, including an empty resultRecordHit. A parry or a block costs the attacker that swing.
A record carries what the swing landed on, and that decides when the target comes back. The level does not. A combatant that took nothing returns as soon as it starts taking hits, so a boss dropping its invulnerability partway through a swing is reachable by that same swing.
Overriding HandleDamageResult replaces that rule outright, so call RecordHit yourself for the hits you mean to keep; both it and CanHitActor are Blueprint-callable. GetTargetsHitThisWindow counts the targets a swing has spent itself on, for damage falloff across a cleave.
HitResetInterval: 0 allows one recorded hit per target per window. Above 0, the same target can register again after that many seconds; expired records purge each tick. An attack needing its own rate sets Multi Hit Interval on its damage config, which takes over for that window and ends with it.
AdvancedDebug
SEC.Debug.Melee.DrawTracing 1
Component Draw Debug, or notify Enable Debug Draw for one window (bSessionDebugOverride).
AdvancedCommon issues
ProblemLikely causeFix
No hitsSocketIDs ≠ socket IDMatch FName strings.
No hitsSockets missingEquip the weapon so its sockets register; the wielder needs a trace component.
Miss first active frameWarm-up tickNormal: sweep needs a prior position sample.
Through wallsTrace FilterObject Types mode reports every listed target along the whole span and nothing stops it, so the level shields nothing. Use Channel mode for occlusion.
Wall plays the flesh cueWall reads as a targetA wall with Can Be Damaged on and no interface sorts as Damageable. Switch the flag off on level geometry, or tick Require Damageable Target.
Volume in front of a character eats its hitsSensor collider set to BlockSet that collider's response to the trace channel to Overlap, and list its component tag under Sense Component Tags. The log names the component.
Corpse keeps ringingEffect runs on inert hitsUntick Run On Inert Hits on that effect, or switch Can Be Damaged off on death so the body sorts as inert in the first place.
Two hits one swingHit Reset Interval above zero, or two windows overlapping on the montageOne target takes one hit per window at zero. Check the interval, the config's Multi Hit Interval, and the Output Log for an overlap warning.
No damage on SEC pawnNo interfaceImplement ISECDamageable.
Client swing, no damageNo authorityDetection runs on the authority. Override ShouldDetectHits to sweep on the owning client instead.
The component reports several of these itself. Check the Output Log before hunting: it names a socket a window asked for that nothing registered, a window that opened while another was still open, a socket sweeping from a mesh that is not refreshing its bones, an Object Types filter with an empty list, and a sensor collider blocking the trace channel.