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 |
Related Documentation¶
- Combat Overview - Hit processing in CombatComponent
- Combo System - Hit window timing
- Combat Animation - Animation notify setup
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.