Skip to content

Hit Tracing

The Hit Tracing System detects weapon and body part collisions using socket-based traces. Multiple trace profiles can be registered independently, each with its own mesh, sockets, and trace method. Animation notifies control when traces are active.

Architecture

+---------------------------+
| UHitTraceActorComponent   |
+---------------------------+
           |
           v
+---------------------------+
|  TraceProfiles (TMap)     |
+---------------------------+
| Tag: Trace.Weapon.Right   |-----> FHitTraceProfile
|   TraceMesh: WeaponMesh   |       +--SocketNames[]
|   TraceMethod: OverTime   |       +--LastSocketLocations{}
|                           |       +--bIsActive
| Tag: Trace.Weapon.Left    |-----> FHitTraceProfile
|   TraceMesh: OffhandMesh  |       ...
|                           |
| Tag: Trace.Body.Hand.R    |-----> FHitTraceProfile
|   TraceMesh: CharacterMesh|       ...
+---------------------------+
           |
           v (when active)
+---------------------------+
| TickComponent()           |
| - TraceSameSocketOverTime |
| - TraceBetweenSockets     |
+---------------------------+
           |
           v (on hit)
+---------------------------+
| OnItemAdded.Broadcast()   |
+---------------------------+
           |
           v
+---------------------------+
| UCombatComponent          |
| ::OnActorHit()            |
+---------------------------+

Why This Design?

Profile-Based Architecture

Instead of hardcoding "weapon trace" and "body trace," the system uses tagged profiles. This allows: - Multiple weapons (dual-wield) with independent traces - Body part traces for unarmed combat - Easy addition of new trace sources (tails, wings, etc.)

Socket-Based Tracing

Traces use mesh sockets rather than bones or fixed offsets. This means: - Weapon artists can place sockets for optimal trace coverage - Different weapons can have different socket layouts - No code changes needed for new weapon shapes

Delta-Time Tracing

Traces compare positions between frames rather than checking a single point. This catches fast-moving weapons that might teleport through targets in a single frame.

Trace Methods

The system supports three trace methods for different use cases:

SameSocketOverTime (Default)

Traces from each socket's previous position to its current position.

Frame N:   Socket_01 at position A
Frame N+1: Socket_01 at position B
Trace:     A =================> B

Best for: Swinging weapons, following arc of attack

BetweenSocketsSameTime

Traces between different sockets in the same frame.

Frame N:
  Socket_01 =================== Socket_02
       ||                            ||
       ||                            ||
  Socket_03 =================== Socket_04

Best for: Blade edges, polearm shafts

BetweenSocketsDifferentTime

Traces from each socket's current position to other sockets' previous positions.

Frame N:     Socket_01(A)  Socket_02(B)
Frame N+1:   Socket_01(C)  Socket_02(D)
Traces:      C ---------> B
             D ---------> A

Best for: Maximum coverage on fast attacks

Trace Profile Configuration

FHitTraceProfile Properties

Property Type Purpose
TraceMesh UPrimitiveComponent* Mesh containing trace sockets
SocketNames TArray Explicit sockets (empty = all sockets)
TraceMethod ETraceMethod Which trace algorithm to use
SkipStringFilter FString Exclude sockets with this substring
InclusionStringFilter FString Only include sockets with this substring
bIsActive bool Whether currently tracing
LastSocketLocations TMap Previous frame positions

Profile Tags

Tag Typical Use
Trace.Weapon.Right Main hand weapon
Trace.Weapon.Left Off-hand weapon
Trace.Body.Hand.Right Right fist (unarmed)
Trace.Body.Hand.Left Left fist (unarmed)
Trace.Body.Foot.Right Kick attacks
Trace.Body.Foot.Left Kick attacks

How Tracing Works

Registration Flow

Weapon equipped
       |
       v
EquipmentComponent spawns weapon actor
       |
       v
Get weapon's SkeletalMeshComponent
       |
       v
HitTraceActorComponent::RegisterTraceProfile()
       |
       +---> Create FHitTraceProfile
       +---> Store in TraceProfiles map
       +---> Profile starts inactive

Activation Flow

Attack animation plays
       |
       v
ComboHitWindow notify begins
       |
       v
HitTraceActorComponent::ToggleTraceCheck(true, ProfileTag)
       |
       +---> Find profile by tag
       +---> Set bIsActive = true
       +---> Initialize LastSocketLocations
       +---> Add to ActiveProfileTags
       +---> Set CanTrace = true
       |
       v
TickComponent runs traces
       |
       v
ComboHitWindow notify ends
       |
       v
ToggleTraceCheck(false, ProfileTag)
       |
       +---> Deactivate profile
       +---> Clear hit array

Hit Detection Flow

TickComponent()
       |
       v
For each active profile:
       |
       +---> Get filtered sockets
       +---> Execute trace method
       |
       v
PerformTrace(Start, End)
       |
       +---> Check distance threshold
       +---> Execute shape trace (sphere/box/capsule/line)
       |
       v
For each hit result:
       |
       +---> Already hit this actor? -> Skip
       +---> Add to HitArray
       +---> OnItemAdded.Broadcast(HitResult)

Trace Shape Configuration

Property Type Default Purpose
TraceType EKismetTraceType SphereTrace Shape of trace
SphereRadius float 10.0 Radius for sphere traces
BoxHalfSize FVector (5,5,5) Half-extents for box traces
CapsuleRadius float 5.0 Radius for capsule traces
CapsuleHalfHeight float 20.0 Half-height for capsule traces
bTraceComplex bool true Use complex collision
bIgnoreSelf bool true Ignore owning actor

Animation Integration

The ComboHitWindow notify state controls trace activation:

Montage Timeline:
|---[Startup]---|---[Active Frames]---|---[Recovery]---|
                |                     |
                | <-- HitWindow -->   |
                |                     |
          NotifyBegin()          NotifyEnd()
                |                     |
                v                     v
        ToggleTrace(true)    ToggleTrace(false)

ComboHitWindow Properties

Property Purpose
WeaponTraceTag Which profile to activate
bIsFinalHit Mark last hit in combo
HitDamageMultiplier Optional per-hit damage modifier

Duplicate Prevention

The system prevents hitting the same actor multiple times per attack:

New hit detected
       |
       v
HitArray.ContainsByPredicate(
    [&](FHitResult& Existing) {
        return Existing.GetActor() == Hit.GetActor();
    }
)
       |
  +----+----+
  |         |
Found    Not Found
  |         |
  v         v
Skip     Add to array
         Broadcast

The HitArray is cleared when traces are deactivated at the end of the hit window.

Key Contracts

UHitTraceActorComponent API

Method Parameters Purpose
RegisterTraceProfile() Tag, Mesh, Sockets, Method, Filters Create new trace profile
UnregisterTraceProfile() Tag Remove profile
UpdateProfileMesh() Tag, NewMesh Change profile's trace mesh
ToggleTraceCheck() bTrace, Tag Enable/disable specific profile
ClearAllActiveTraces() - Stop all tracing, clear hits

OnItemAdded Delegate

Parameter Type Contents
LastItem FHitResult Hit location, actor, component, bone

Source References

Concept File Line
UHitTraceActorComponent class Source/ProjectEternal/Public/Combat/Components/HitTraceActorComponent.h 30
FHitTraceProfile struct Source/ProjectEternal/Public/Combat/Components/HitTraceActorComponent.h 15
ETraceMethod enum Source/ProjectEternal/Public/Combat/Components/HitTraceActorComponent.h 10
TraceSameSocketOverTime() Source/ProjectEternal/Private/Combat/Components/HitTraceActorComponent.cpp 150
RegisterTraceProfile() Source/ProjectEternal/Private/Combat/Components/HitTraceActorComponent.cpp 60
ToggleTraceCheck() Source/ProjectEternal/Private/Combat/Components/HitTraceActorComponent.cpp 100
ComboHitWindow notify Source/ProjectEternal/Public/Combat/AnimNotifies/ComboAnimNotifies.h 10

Recent Changes

  • Profile mesh can be updated dynamically: UpdateProfileMesh() allows changing the traced mesh without re-registering (useful for weapon swapping).
  • Socket filtering improved: Both skip and inclusion filters can be applied simultaneously for precise socket selection.