# BPC_MeleeSystem — Melee Weapon Component ## Blueprint Spec — UE 5.5–5.7 --- ### Parent Class `ActorComponent` ### Dependencies - [`BPC_DamageReceptionSystem`](BPC_DamageReceptionSystem.md) - [`BPC_CombatFeedbackComponent`](54_BPC_CombatFeedbackComponent.md) - [`I_Damageable`](../01-core/03_I_InterfaceLibrary.md) - [`DA_WeaponData`](../14-data-assets/) - Owner Character Animation Blueprint ### Purpose Melee weapon specialization. Handles swing detection, hitbox overlap checking during windup / active frames, and combo chain sequencing. Supports light attacks, heavy attacks, charge attacks, and block/parry. ### Variables | Name | Type | Description | |------|------|-------------| | `ComboSection` | FName | Active montage section for combo | | `ComboStep` | Int | Current combo step index | | `bCanCombo` | Bool | True during window after hit or end of swing | | `ComboWindowDuration` | Float | Seconds to chain next attack | | `SwingMontage` | UAnimMontage | Full melee animation set | | `HitDetectionCollision` | UCapsuleComponent | Overlap collision for hit detection | | `bHitRegistered` | Bool | Prevents multi-hit on same swing | | `HitActors` | Array | Already hit this swing | | `SwingPhase` | ESwingPhase | Windup / Active / Recovery / Idle | | `ChargeDuration` | Float | Hold time for charged heavy attack | | `bIsBlocking` | Bool | Currently blocking stance | | `ParryWindow` | Float | Active parry frames in seconds | | `bParryActive` | Bool | Within parry active window | | `StaggerDuration` | Float | Hit reaction stun (self or target) | ### Enums | Enum | Values | Description | |------|--------|-------------| | `ESwingPhase` | Idle, WindUp, Active, Recovery, ParryWindow | Attack animation phase | | `EAttackType` | LightAttack, HeavyAttack, ChargeAttack, SprintAttack, ParryRiposte | Swing variant | ### Functions | Name | Inputs | Outputs | Description | |------|--------|---------|-------------| | `StartSwing` | AttackType: EAttackType | — | Play montage section, set SwingPhase | | `OnSwingWindup` | — | — | Begin hit detection | | `OnSwingActive` | — | — | Enable HitDetectionCollision overlap | | `OnSwingHit` | HitResult: FHitResult | — | Single hit registration | | `OnSwingRecovery` | — | — | Disable hit collision, check combo window | | `OnSwingComplete` | — | — | Return to Idle | | `StartBlock` | — | — | Play blocking animation | | `EndBlock` | — | — | Release block stance | | `ParryCheck` | IncomingAttack | Bool | If parry window active → counter | | `GetComboStep` | — | Int | Return current combo index | | `ResetCombo` | — | — | Clear combo step counter | ### Blueprint Flow ``` [Combo Chain Logic] LightAttackInput → If SwingPhase == Idle: ComboStep = 0 StartSwing(LightAttack) ElseIf SwingPhase == Active || SwingPhase == Recovery: If bCanCombo && ComboStep < MaxComboLength: ComboStep++ StartSwing(LightAttack) — next section of montage [OnSwingActive — called by Animation Notify] └─► HitDetectionCollision.SetCollisionEnabled(QueryOnly) └─► On overlap → OnSwingHit [OnSwingHit] └─► If HitActor already in HitActors → return └─► Add HitActor to HitActors └─► If HitActor implements I_Damageable: BPC_DamageReceptionSystem.ApplyMeleeDamage( Damage = WeaponData.Damage * AttackTypeMultiplier, HitActor, HitLocation, ImpulseDirection ) └─► BPC_CombatFeedbackComponent.PlayHitFX(HitResult) └─► ApplyStagger(HitActor) [OnSwingRecovery — called by Animation Notify] └─► HitDetectionCollision.SetCollisionEnabled(NoCollision) └─► HitActors.Empty └─► Set bCanCombo = true └─► Start timer for ComboWindowDuration └─► If no combo input received → OnSwingComplete [OnSwingComplete] └─► SwingPhase = Idle └─► bCanCombo = false └─► ComboStep = 0 [StartBlock] └─► bIsBlocking = true └─► Play block montage loop section └─► Owner movement speed reduced [ParryCheck] └─► If bParryActive && incoming swing phase == Active: Play parry riposte animation Stagger incoming attacker Return true └─► Return false ``` ### Communications With | Target | Method | Why | |--------|--------|-----| | [`BPC_DamageReceptionSystem`](BPC_DamageReceptionSystem.md) | Get Component | Apply melee damage and stagger | | [`BPC_CombatFeedbackComponent`](54_BPC_CombatFeedbackComponent.md) | Get Component | Swing whoosh, hit impact, block sparks | | Owner Animation Blueprint | Direct | Query SwingPhase for animation state | | Owner Character Movement | Direct | Reduce speed during block | | Owner Character Input | Direct | Light / Heavy / Block input mapping | | [`I_Damageable`](../01-core/03_I_InterfaceLibrary.md) | Interface | Damage application on hit actors | ### Reuse Notes - Uses animation notifies for phase transitions (Notify_Windup, Notify_Active, Notify_Recovery, Notify_CanCombo, Notify_ParryWindow). - Combo system uses montage section names "Combo_1", "Combo_2", etc. - Hit collision is a simple box or capsule that exists only during Active phase. - Block reduces incoming damage via DamageReception; parry reflects stagger. - Renamed from `BP_MeleeWeapon` to `BPC_MeleeSystem` per Master naming convention. - Cross-references updated: `BPC_DamageHandlerComponent` → `BPC_DamageReceptionSystem`. --- ## Manual Implementation Guide ### Class Setup 1. Create Blueprint Class: Parent = `ActorComponent`, Name = `BPC_MeleeSystem` 2. Attach to `BP_WeaponBase` subclass: `BP_MeleeWeapon` 3. Add `HitDetectionCollision` (Capsule or Box component) to weapon — disabled by default ### Variable Init (BeginPlay) ``` Event BeginPlay ├─ Set SwingPhase = Idle ├─ Set ComboStep = 0 ├─ Set bCanCombo = false ├─ Set bIsBlocking = false ├─ Disable HitDetectionCollision (NoCollision) ├─ Get Owner Weapon → Read DA_WeaponData for: ComboWindowDuration, ChargeDuration, ParryWindow, StaggerDuration └─ Get Owner → Find BPC_DamageReceptionSystem → Cache ``` ### Function Implementations #### `StartSwing(AttackType: EAttackType)` → `void` ``` [Function: StartSwing] Step 1: Branch on SwingPhase != Idle AND SwingPhase != Recovery → Return (can't chain now) Step 2: Set SwingPhase = WindUp Step 3: Build montage section name: If this is combo: "Combo_" + ComboStep If AttackType == HeavyAttack: prefix "Heavy_" If AttackType == ChargeAttack: "Charge_" Step 4: Play Montage (SwingMontage, Section = built section name) Step 5: Set bHitRegistered = false, Clear HitActors array Step 6: Fire OnSwingStarted(AttackType, ComboStep) ``` **Nodes:** `Switch on EAttackType`, `Build String`, `Play Montage` (with Starting Section), `Clear Array` #### `OnSwingActive()` → `void` *(Called by Animation Notify: "Notify_Active")* ``` Step 1: Set SwingPhase = Active Step 2: HitDetectionCollision.SetCollisionEnabled(QueryOnly) Step 3: Set bHitRegistered = false ``` #### `OnSwingHit(HitResult)` → `void` *(Called by HitDetectionCollision OnComponentBeginOverlap)* ``` Step 1: Get Hit Actor from Overlap → Cast to Actor Step 2: ForEach HitActors → if match found → Return (already hit this actor this swing) Step 3: Add HitActor to HitActors Step 4: If HitActor implements I_Damageable: Get BPC_DamageReceptionSystem → Call ApplyMeleeDamage: BaseDamage = WeaponData.Damage Multiplier: Light=1.0, Heavy=1.8, Charge=2.5, Sprint=1.5 HitLocation = HitResult.ImpactPoint Apply impulse in swing direction Step 5: Get BPC_CombatFeedbackComponent → Call PlayHitFX(HitResult) Step 6: Apply Stagger to HitActor ``` #### `OnSwingRecovery()` → `void` *(Animation Notify: "Notify_Recovery")* ``` Step 1: Set SwingPhase = Recovery Step 2: HitDetectionCollision.SetCollisionEnabled(NoCollision) Step 3: Clear HitActors Step 4: Set bCanCombo = true Step 5: Start Timer (ComboWindowDuration) → On timer: if no combo received → OnSwingComplete() ``` #### `OnSwingComplete()` → `void` ``` Step 1: Set SwingPhase = Idle Step 2: Set bCanCombo = false Step 3: Set ComboStep = 0 Step 4: Fire OnSwingFinished ``` #### `StartBlock()` → `void` ``` Step 1: Set bIsBlocking = true Step 2: Play block montage loop section Step 3: Get Owner Character → Get CharacterMovement → Set MaxWalkSpeed *= 0.5 Step 4: Set ParryWindow timer: bParryActive = true for ParryWindow seconds On timer end → bParryActive = false ``` #### `EndBlock()` → `void` ``` Step 1: Set bIsBlocking = false Step 2: Stop block montage Step 3: Restore MaxWalkSpeed ``` ### Build Checklist - [ ] Create BPC_MeleeSystem, add to BP_MeleeWeapon - [ ] Add HitDetectionCollision component (Capsule/Box, NoCollision by default) - [ ] Create SwingMontage with sections: Combo_1, Combo_2, Combo_3, Heavy_1, Charge_1 - [ ] Place Animation Notifies: Notify_Active, Notify_Recovery, Notify_CanCombo, Notify_ParryWindow - [ ] Implement phase state machine: Idle→WindUp→Active→Recovery→(combo)→Idle - [ ] Bind HitDetectionCollision.OnComponentBeginOverlap → OnSwingHit - [ ] Implement combo system with bCanCombo window timer - [ ] Implement block/parry with damage reduction and stagger reflection