feat: Enhance interaction and inventory systems with new components and functionality
- Added BPC_UsableWorldObjectSystem for handling various interactable world objects with detailed manual implementation guide. - Introduced BPC_ActiveItemSystem to manage quick slots and active item usage, including cycling and selection logic. - Implemented BPC_DocumentArchiveSystem for managing collectible documents with read tracking and categorization. - Developed BPC_JournalSystem for narrative entries with auto-adding features based on gameplay events. - Created BPC_KeyItemSystem for key management with consumable and persistent key support. - Enhanced BPC_FirearmSystem for ranged weapon mechanics, including hitscan and projectile firing. - Updated BPC_MeleeSystem for melee combat with combo and blocking mechanics. - Established BPC_ReloadSystem for managing weapon reloading processes, including partial reloads and state management.
This commit is contained in:
@@ -102,4 +102,61 @@ Ranged weapon specialization. Handles line trace / projectile fire, weapon sprea
|
||||
- Spread is cumulative while firing, resets on recovery timer.
|
||||
- Projectile type requires a child BP implementing `AP_BaseProjectile` with velocity and lifetime.
|
||||
- Renamed from `BP_RangedWeapon` to `BPC_FirearmSystem` per Master naming convention.
|
||||
- Cross-references updated: `BPC_DamageHandlerComponent` → `BPC_DamageReceptionSystem`, `BPC_PlayerCameraManager` → `BPC_CameraStateLayer`, `DA_WeaponData` → `14-data-assets/`.
|
||||
- Cross-references updated: `BPC_DamageHandlerComponent` → `BPC_DamageReceptionSystem`, `BPC_PlayerCameraManager` → `BPC_CameraStateLayer`, `DA_WeaponData` → `14-data-assets/`.
|
||||
|
||||
---
|
||||
|
||||
## Manual Implementation Guide
|
||||
|
||||
### Class Setup
|
||||
1. Create Blueprint Class: Parent = `ActorComponent`, Name = `BPC_FirearmSystem`
|
||||
2. Attach to `BP_WeaponBase` subclass: `BP_RangedWeapon`
|
||||
3. Add FireSocket SceneComponent on weapon mesh (muzzle position)
|
||||
|
||||
### Variable Init (BeginPlay)
|
||||
```
|
||||
Event BeginPlay
|
||||
├─ Read WeaponData from Owner BP_WeaponBase
|
||||
├─ Set FireType = WeaponData.FireType (Hitscan/Projectile/Hybrid)
|
||||
├─ Set Range = WeaponData.EffectiveRange
|
||||
├─ Set SpreadAngle = WeaponData.BaseSpread
|
||||
├─ Set BulletsPerShot = WeaponData.PelletsPerShot
|
||||
├─ Set CurrentSpread = 0.0
|
||||
└─ Cache: BPC_AmmoComponent, BPC_CombatFeedbackComponent, BPC_CameraStateLayer
|
||||
```
|
||||
|
||||
### Function Node-by-Node
|
||||
|
||||
#### `OnFire_Implementation()` *(Overrides BP_WeaponBase.OnFire)*
|
||||
```
|
||||
Step 1: Get Camera Forward Vector
|
||||
Step 2: Switch on FireType:
|
||||
Hitscan: ForLoop (BulletsPerShot):
|
||||
AimDir = Forward + CalculateSpread()
|
||||
LineTraceByChannel: Start=Camera, End=Camera+AimDir*Range
|
||||
If Hit & Implements I_Damageable: ApplyDamage(WeaponData.Damage, HitResult)
|
||||
SpawnImpactFX(HitResult)
|
||||
Projectile: ForLoop (BulletsPerShot):
|
||||
Spawn ProjectileClass at FireSocket, velocity=AimDir*Speed
|
||||
Hybrid: Hitscan + projectile for near-miss area
|
||||
Step 3: ApplyRecoil → CameraShake or AddControllerPitch/Yaw
|
||||
Step 4: ConsumeAmmo on BPC_AmmoComponent
|
||||
Step 5: PlayMuzzleFlash + PlayFireSound on CombatFeedback
|
||||
Step 6: CurrentSpread += SpreadIncreasePerShot (clamped to MaxSpread)
|
||||
```
|
||||
|
||||
#### `CalculateSpread()` → Vector *(Pure)*
|
||||
```
|
||||
RandomFloat(-1,1)*CurrentSpread → YawOffset
|
||||
RandomFloat(-1,1)*CurrentSpread → PitchOffset
|
||||
MakeRotator(PitchOffset, YawOffset, 0) → GetForwardVector
|
||||
```
|
||||
|
||||
### Build Checklist
|
||||
- [ ] Create BPC_FirearmSystem, attach to BP_RangedWeapon
|
||||
- [ ] Add FireSocket at muzzle
|
||||
- [ ] Implement OnFire with hitscan/projectile/hybrid switch
|
||||
- [ ] Implement CalculateSpread
|
||||
- [ ] Wire to AmmoComponent, CombatFeedback, CameraStateLayer
|
||||
- [ ] Create ProjectileClass with ProjectileMovement for projectile weapons
|
||||
- [ ] Test: fire at target → damage registers → FX plays → ammo count drops
|
||||
@@ -131,4 +131,115 @@ Melee weapon specialization. Handles swing detection, hitbox overlap checking du
|
||||
- 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`.
|
||||
- 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
|
||||
@@ -59,4 +59,106 @@
|
||||
|
||||
- ReloadMontage from DA_WeaponData per weapon; swap for each weapon type
|
||||
- Partial reload enabled per weapon (e.g. shotguns use individual shell reloads)
|
||||
- AmmoTypeTag links to correct ammo pool in BPC_AmmoResourceSystem
|
||||
- AmmoTypeTag links to correct ammo pool in BPC_AmmoResourceSystem
|
||||
|
||||
---
|
||||
|
||||
## Manual Implementation Guide
|
||||
|
||||
### Class Setup
|
||||
1. Create Blueprint Class: Parent = `ActorComponent`, Name = `BPC_ReloadSystem`
|
||||
2. Attach to `BP_WeaponBase` or `BPC_FirearmSystem`
|
||||
3. Weapon must have a `ReloadMontage` with Animation Notifies
|
||||
|
||||
### Variable Init (BeginPlay)
|
||||
```
|
||||
Event BeginPlay
|
||||
├─ Set bIsReloading = false
|
||||
├─ Set bPartialReload = false
|
||||
├─ Get Owner → Read DA_WeaponData → Load ReloadMontage, AmmoTypeTag, MagazineSize
|
||||
└─ Cache: BPC_AmmoComponent, BP_WeaponBase (for state check)
|
||||
```
|
||||
|
||||
### Function Implementations
|
||||
|
||||
#### `RequestReload()` → `void`
|
||||
|
||||
```
|
||||
[Function: RequestReload]
|
||||
Step 1: Get BP_WeaponBase → Check WeaponState == Ready → If not, return (can't reload while firing)
|
||||
Step 2: Call CanReload() → Branch:
|
||||
False → Fire OnReloadFailed → Return
|
||||
True → Call BeginReload()
|
||||
```
|
||||
|
||||
#### `CanReload()` → `Boolean`
|
||||
|
||||
```
|
||||
[Function: CanReload] (Pure)
|
||||
Step 1: Get BPC_AmmoComponent → Call GetAmmoInMagazine()
|
||||
If magazine >= MagazineSize → Return false (already full)
|
||||
Step 2: Get BPC_AmmoComponent → Call GetReserveAmmo(AmmoTypeTag)
|
||||
If reserve <= 0 → Return false (no ammo to load)
|
||||
Step 3: Return true
|
||||
```
|
||||
|
||||
#### `BeginReload()` → `void`
|
||||
|
||||
```
|
||||
[Function: BeginReload]
|
||||
Step 1: Set bIsReloading = true
|
||||
Step 2: Notify BP_WeaponBase → SetWeaponState(Reloading)
|
||||
Step 3: Play Montage (ReloadMontage)
|
||||
Step 4: Fire OnReloadStarted
|
||||
|
||||
Step 5: Animation Notify "TransferRounds" setup:
|
||||
In the animation montage, add Notify at the frame where the magazine is inserted.
|
||||
On trigger → Call CompleteReload()
|
||||
|
||||
Step 6: Animation Notify "ReloadEnd" setup:
|
||||
Add Notify at montage end → Call FinishReload()
|
||||
```
|
||||
|
||||
#### `CompleteReload()` → `void` *(Called by Notify "TransferRounds")*
|
||||
|
||||
```
|
||||
[Function: CompleteReload]
|
||||
Step 1: Get BPC_AmmoComponent:
|
||||
MagazineCurrent = GetAmmoInMagazine()
|
||||
ReserveCurrent = GetReserveAmmo(AmmoTypeTag)
|
||||
Step 2: RoundsToAdd = Min(MagazineSize - MagazineCurrent, ReserveCurrent)
|
||||
Step 3: BPC_AmmoComponent.RemoveReserveAmmo(AmmoTypeTag, RoundsToAdd)
|
||||
Step 4: BPC_AmmoComponent.AddMagazineAmmo(RoundsToAdd)
|
||||
```
|
||||
|
||||
#### `FinishReload()` → `void` *(Called by Notify "ReloadEnd")*
|
||||
|
||||
```
|
||||
Step 1: Set bIsReloading = false
|
||||
Step 2: Notify BP_WeaponBase → SetWeaponState(Ready)
|
||||
Step 3: Fire OnReloadCompleted(RoundsToAdd)
|
||||
```
|
||||
|
||||
#### `InterruptReload()` → `void`
|
||||
|
||||
```
|
||||
[Function: InterruptReload]
|
||||
Step 1: Branch on bIsReloading → If false, return
|
||||
Step 2: If bPartialReload AND CompleteReload already called:
|
||||
Keep transferred rounds (partial reload success)
|
||||
Step 3: Else: no rounds transferred
|
||||
Step 4: Stop Montage (ReloadMontage)
|
||||
Step 5: Set bIsReloading = false
|
||||
Step 6: Notify BP_WeaponBase → SetWeaponState(Ready)
|
||||
Step 7: Fire OnReloadInterrupted(RoundsTransferred)
|
||||
```
|
||||
|
||||
### Build Checklist
|
||||
- [ ] Create BPC_ReloadSystem, add to BP_RangedWeapon
|
||||
- [ ] Create ReloadMontage per weapon with Notifies: TransferRounds, ReloadEnd
|
||||
- [ ] Implement CanReload checking magazine fullness and reserve ammo
|
||||
- [ ] Implement BeginReload with montage playback and state lock
|
||||
- [ ] Wire CompleteReload to ammo transfer
|
||||
- [ ] Wire FinishReload to state restoration
|
||||
- [ ] Implement InterruptReload for mid-reload weapon swap
|
||||
- [ ] Test: empty magazine → reload → rounds transfer → magazine full
|
||||
Reference in New Issue
Block a user