257 lines
11 KiB
Markdown
257 lines
11 KiB
Markdown
# BPC_HitReactionSystem — Hit Reaction System
|
||
|
||
> **⚡ C++ Status: Stub** — `Source/PG_Framework/Public/Weapons/BPC_HitReactionSystem.h` provides the UCLASS shell, `PlayHitReaction()` stub, `FlinchThreshold`, and `RagdollThreshold`. **The C++ stub has NO gameplay logic.** **Create a BP child** and build ALL logic: hit reaction animation selection, stagger/knockdown/ragdoll trigger, directional response, camera trauma. Attach to player/enemy pawns. See `docs/developer/cpp-integration-guide.md`.
|
||
>
|
||
> ---
|
||
|
||
## Blueprint Spec — UE 5.5–5.7
|
||
|
||
---
|
||
|
||
### Parent Class
|
||
`ActorComponent`
|
||
|
||
### Dependencies
|
||
- **Requires:** [`BPC_HealthSystem`](../02-player/08_BPC_HealthSystem.md) — Receives damage events
|
||
- **Requires:** [`BPC_CameraStateLayer`](../02-player/14_BPC_CameraStateLayer.md) — Camera trauma effects
|
||
- **Requires:** [`S_DamageEvent`](../02-player/08_BPC_HealthSystem.md) — Damage event struct (E_DamageType, Amount, HitLocation, HitNormal)
|
||
- **Requires:** [`E_DamageType`](../01-core/03_I_InterfaceLibrary.md) — Damage type enum for montage selection
|
||
- **Required By:** [`BPC_AdaptiveEnvironmentDirector`](../10-adaptive/BPC_AdaptiveEnvironmentDirector.md) — Reads trauma intensity for atmosphere
|
||
- **Engine/Plugin Requirements:** Animation Blueprint (ABP_PlayerBody), GASP animation hooks
|
||
|
||
### Purpose
|
||
Drives physical hit reaction behaviour: flinch animations, ragdoll blends, and camera trauma. Processes incoming damage events and triggers appropriate reaction animations based on damage magnitude, direction, and type.
|
||
|
||
---
|
||
|
||
## 1. Enums
|
||
|
||
*Uses `E_DamageType` from [`BPC_HealthSystem`](../02-player/08_BPC_HealthSystem.md) — Physical, Fire, Psychic, Environmental, InstantKill, Scripted.*
|
||
|
||
---
|
||
|
||
## 2. Structs
|
||
|
||
*No new structs defined. Uses `S_DamageEvent` from [`BPC_HealthSystem`](../02-player/08_BPC_HealthSystem.md).*
|
||
|
||
---
|
||
|
||
## 3. Variables
|
||
|
||
### Configuration (Instance Editable, Expose On Spawn)
|
||
|
||
| Variable | Type | Default | Category | Description |
|
||
|----------|------|---------|----------|-------------|
|
||
| `FlinchThreshold` | Float | 5.0 | HitReaction | Minimum damage to trigger flinch animation |
|
||
| `RagdollThreshold` | Float | 50.0 | HitReaction | Damage amount that triggers ragdoll blend |
|
||
| `TraumaDecayRate` | Float | 2.0 | HitReaction | Camera trauma points recovered per second |
|
||
| `HitReactionMontages` | Map (E_DamageType → AnimMontage) | Empty | HitReaction | Per-damage-type hit reaction animations |
|
||
|
||
### Internal (Private / Protected, No Expose)
|
||
|
||
| Variable | Type | Default | Category | Description |
|
||
|----------|------|---------|----------|-------------|
|
||
| `CurrentTrauma` | Float | 0.0 | Internal | Accumulated camera trauma level |
|
||
| `bIsReacting` | Bool | False | Internal | Reaction animation currently playing |
|
||
| `LastDamageDirection` | Vector | (0,0,0) | Internal | Direction of most recent damage for animation blend |
|
||
| `NextReactionIndex` | Integer | 0 | Internal | Cycles through available montages per type for variety |
|
||
|
||
---
|
||
|
||
## 4. Functions
|
||
|
||
### Public Functions
|
||
|
||
#### `ProcessHitReaction` → `void`
|
||
- **Description:** Main entry point. Called when player receives damage. Determines reaction type based on damage amount vs thresholds.
|
||
- **Parameters:**
|
||
| Param | Type | Description |
|
||
|-------|------|-------------|
|
||
| `DamageEvent` | S_DamageEvent | Full damage context from HealthSystem |
|
||
- **Blueprint Authority:** Any
|
||
- **Flow:** Checks thresholds → selects montage → plays animation → applies trauma → broadcasts dispatchers
|
||
|
||
#### `ApplyTrauma` → `void`
|
||
- **Description:** Adds camera trauma based on damage amount.
|
||
- **Parameters:**
|
||
| Param | Type | Description |
|
||
|-------|------|-------------|
|
||
| `Amount` | Float | Trauma points to add |
|
||
- **Blueprint Authority:** Any
|
||
|
||
#### `GetCurrentTrauma` → `Float`
|
||
- **Description:** Returns current accumulated trauma level (0–100).
|
||
- **Parameters:** None
|
||
- **Blueprint Authority:** Any
|
||
|
||
#### `ResetTrauma` → `void`
|
||
- **Description:** Clears all accumulated camera trauma to zero.
|
||
- **Parameters:** None
|
||
- **Blueprint Authority:** Any
|
||
|
||
### Protected / Private Functions
|
||
|
||
#### `SelectHitReactionMontage` → `AnimMontage`
|
||
- **Description:** Picks a hit reaction montage based on damage type and cycles through available options for variety.
|
||
- **Parameters:**
|
||
| Param | Type | Description |
|
||
|-------|------|-------------|
|
||
| `DamageType` | E_DamageType | Type of damage received |
|
||
| `DamageAmount` | Float | Magnitude of damage |
|
||
- **Flow:** Look up HitReactionMontages map by damage type → cycle through entries → return selected montage
|
||
|
||
#### `TickTraumaDecay` → `void`
|
||
- **Description:** Called on tick to decay camera trauma toward zero at TraumaDecayRate.
|
||
- **Parameters:**
|
||
| Param | Type | Description |
|
||
|-------|------|-------------|
|
||
| `DeltaTime` | Float | Frame delta time |
|
||
- **Flow:** `CurrentTrauma = FMath::FInterpTo(CurrentTrauma, 0.0, DeltaTime, TraumaDecayRate)`
|
||
|
||
---
|
||
|
||
## 5. Event Dispatchers
|
||
|
||
| Dispatcher | Parameters | Bind Access | Description |
|
||
|------------|-----------|-------------|-------------|
|
||
| `OnFlinchTriggered` | DamageType: E_DamageType, Amount: Float | Public | Flinch animation fired (damage below ragdoll threshold) |
|
||
| `OnRagdollBlend` | Amount: Float, Direction: Vector | Public | Ragdoll blend triggered (damage exceeded ragdoll threshold) |
|
||
| `OnTraumaChanged` | CurrentTrauma: Float | Public | Trauma level changed (for camera/screen effects) |
|
||
| `OnHitReactionComplete` | DamageType: E_DamageType | Public | Reaction animation finished playing |
|
||
|
||
---
|
||
|
||
## 6. Overridden Events / Custom Events
|
||
|
||
### Event: `ReceiveDamage`
|
||
- **Description:** Called by [`BPC_DamageReceptionSystem`](BPC_DamageReceptionSystem.md) when player takes damage. Routes to `ProcessHitReaction`.
|
||
- **Flow:**
|
||
1. Extract damage amount and type from DamageEvent
|
||
2. If DamageAmount >= FlinchThreshold → ProcessHitReaction
|
||
3. If DamageAmount >= RagdollThreshold → trigger ragdoll blend instead
|
||
4. Calculate LastDamageDirection from HitLocation relative to player
|
||
5. ApplyTrauma proportional to damage amount
|
||
|
||
---
|
||
|
||
## 7. Blueprint Graph Logic Flow
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[ReceiveDamage called] --> B{Damage >= RagdollThreshold?}
|
||
B -->|Yes| C[Disable input temporarily]
|
||
B -->|No| D{Damage >= FlinchThreshold?}
|
||
C --> E[Play ragdoll physics blend]
|
||
D -->|Yes| F[SelectHitReactionMontage by DamageType]
|
||
D -->|No| G[Skip reaction, only apply trauma]
|
||
F --> H[Play montage with directional blend]
|
||
H --> I[Broadcast OnFlinchTriggered]
|
||
I --> J[Wait for montage end]
|
||
J --> K[Broadcast OnHitReactionComplete]
|
||
E --> L[Set bIsReacting = true]
|
||
L --> M[Wait for ragdoll timer]
|
||
M --> N[Recover from ragdoll]
|
||
N --> K
|
||
G --> O[ApplyTrauma proportional to damage]
|
||
K --> O
|
||
O --> P[Broadcast OnTraumaChanged]
|
||
P --> Q[Camera system reads trauma]
|
||
```
|
||
|
||
---
|
||
|
||
## 8. Communication Matrix
|
||
|
||
| Who Talks | How | What Is Sent |
|
||
|-----------|-----|-------------|
|
||
| [`BPC_DamageReceptionSystem`](BPC_DamageReceptionSystem.md) | Direct call | `S_DamageEvent` |
|
||
| [`BPC_CameraStateLayer`](../02-player/14_BPC_CameraStateLayer.md) | Dispatcher (`OnTraumaChanged`) | `CurrentTrauma: Float` |
|
||
| [`WBP_ScreenEffectController`](../06-ui/WBP_ScreenEffectController.md) | Dispatcher (`OnTraumaChanged`) | `CurrentTrauma: Float` |
|
||
| [`ABP_PlayerBody`](../02-player/13_BPC_EmbodimentSystem.md) | Direct (anim var write) | `LastDamageDirection`, reaction montage reference |
|
||
| [`BPC_AdaptiveEnvironmentDirector`](../10-adaptive/BPC_AdaptiveEnvironmentDirector.md) | Direct read | `CurrentTrauma` via getter |
|
||
|
||
---
|
||
|
||
## 9. Validation / Testing Checklist
|
||
|
||
- [ ] FlinchThreshold: damage at 5.0+ triggers flinch animation
|
||
- [ ] RagdollThreshold: damage at 50.0+ triggers ragdoll blend
|
||
- [ ] TraumaDecayRate: trauma reduces to zero over time when no damage received
|
||
- [ ] HitReactionMontages map: correct montage plays per E_DamageType
|
||
- [ ] Edge case: zero damage events do not trigger any reaction
|
||
- [ ] Edge case: rapid succession hits cycle through montage variations
|
||
- [ ] Edge case: death event (HealthSystem OnDeath) skips flinch, goes directly to ragdoll
|
||
|
||
---
|
||
|
||
## 10. Reuse Notes
|
||
|
||
- FlinchThreshold and RagdollThreshold can be tuned per project for desired combat feel
|
||
- HitReactionMontages map uses E_DamageType as key — add new damage types without modifying core logic
|
||
- Trauma system is separate from camera shake — trauma drives persistent wobble, shake is transient
|
||
- For non-combat projects, set FlinchThreshold very high (e.g., 9999) to disable reactions entirely
|
||
|
||
---
|
||
|
||
*Specification based on Master Section 5.7, line 1821.*
|
||
|
||
---
|
||
|
||
## Manual Implementation Guide
|
||
|
||
### Class Setup
|
||
1. Create Blueprint Class: Parent = `ActorComponent`, Name = `BPC_HitReactionSystem`
|
||
2. Add to Player Character (or EnemyBase)
|
||
3. Create HitReactionMontages per damage type: Physical, Fire, Explosive, etc.
|
||
|
||
### Variable Init (BeginPlay)
|
||
```
|
||
Event BeginPlay
|
||
├─ Set CurrentTrauma = 0.0, bIsReacting = false
|
||
├─ Populate HitReactionMontages map (E_DamageType → AnimMontage)
|
||
├─ Cache: BPC_HealthSystem (bind OnDamageTaken), BPC_CameraStateLayer
|
||
└─ Start TraumaDecay timer (0.1s loop)
|
||
```
|
||
|
||
### Function Node-by-Node
|
||
|
||
#### `ProcessHitReaction(DamageEvent: S_DamageEvent)` → `void`
|
||
```
|
||
Step 1: If bIsReacting → Return (already playing reaction)
|
||
Step 2: Set LastDamageDirection = DamageEvent.HitNormal * -1 ← direction damage came from
|
||
Step 3: If DamageEvent.Amount >= RagdollThreshold:
|
||
Play ragdoll blend: ABP → Set bRagdoll=true, physics blend
|
||
Set bIsReacting = true → timer to recover
|
||
Return
|
||
Step 4: If DamageEvent.Amount >= FlinchThreshold:
|
||
Select montage: HitReactionMontages[DamageEvent.DamageType]
|
||
If multiple: pick NextReactionIndex, cycle it
|
||
Play Montage with blend from LastDamageDirection
|
||
Set bIsReacting = true
|
||
Step 5: Call ApplyTrauma(DamageEvent.Amount * 0.5)
|
||
Step 6: Fire OnHitReactionPlayed(DamageEvent)
|
||
Step 7: On montage complete → Set bIsReacting = false
|
||
```
|
||
|
||
#### `ApplyTrauma(Amount: Float)` → `void`
|
||
```
|
||
Step 1: CurrentTrauma = Min(100, CurrentTrauma + Amount)
|
||
Step 2: Push to camera: BPC_CameraStateLayer.ApplyPostProcessOverride(TraumaVignette, CurrentTrauma/100)
|
||
Step 3: Fire OnTraumaChanged(CurrentTrauma)
|
||
```
|
||
|
||
#### `TraumaDecay Tick` → `void` *(Timer 0.1s)*
|
||
```
|
||
CurrentTrauma = Max(0, CurrentTrauma - TraumaDecayRate * 0.1)
|
||
Update camera effect intensity
|
||
If zero: clear post-process override
|
||
```
|
||
|
||
### Build Checklist
|
||
- [ ] Create BPC_HitReactionSystem, add to Player Character
|
||
- [ ] Create hit reaction montages per damage type
|
||
- [ ] Implement ProcessHitReaction with threshold branching
|
||
- [ ] Implement ApplyTrauma with camera effect push
|
||
- [ ] Set up trauma decay timer
|
||
- [ ] Bind to BPC_HealthSystem.OnDamageTaken
|
||
- [ ] Test: take small hit → flinch; take big hit → ragdoll; trauma decays over time |