完善装弹逻辑
2023年9月7日 2024年1月11日
说明
- 自动装弹时播放动画
- 手动装弹时更新弹药库存
概览
- 定义委托类型, 用于自动装弹
- 提取封装装弹逻辑, 供手动/自动装弹时使用
在武器类定义委托, 需要更换弹夹时进行通知
定义委托, 在弹药用完时行通知客户端
ShootThemUp: Weapon/STUBaseWeapon.h
1DECLARE_MULTICAST_DELEGATE(FOnClipEmptySignature);
添加数据成员
public
ShootThemUp: Weapon/STUBaseWeapon.h
1FOnClipEmptySignature OnClipEmpty;
弹药用完时, 通知客户端, 由客户端负责后续处理
ShootThemUp: Weapon/STUBaseWeapon.cpp
1// DecreaseAmmo 2 3if (IsClipEmpty() && !IsAmmoEmpty()) 4{ 5 // ChangeClip(); 6 OnClipEmpty.Broadcast(); 7}
将ChangeClip改为public, 供武器组件在处理函数中调用
ShootThemUp: Weapon/STUBaseWeapon.h
在武器类中添加接口
是否满足手动更换弹夹条件
- 当前弹夹不是满的
- 还有其他弹夹
ShootThemUp: Weapon/STUBaseWeapon.h
public
1bool CanReload();
ShootThemUp: Weapon/STUBaseWeapon.cpp
1bool ASTUBaseWeapon::CanReload() 2{ 3 return CurrentAmmo.Bullets < DefaultAmmo.Bullets && CurrentAmmo.Clips > 0; 4}
更换弹夹时, 检查剩余弹夹数
DecreaseAmmo中调用ChangeClip时, 已检查过弹药库存; 手动装弹时需要该判断
ShootThemUp: Weapon/STUBaseWeapon.cpp
1void ASTUBaseWeapon::ChangeClip() 2{ 3 if (!CurrentAmmo.Infinite) 4 { 5 if (CurrentAmmo.Clips == 0) 6 { 7 UE_LOG(LogBaseWeapon, Warning, TEXT("No more clips")); 8 return; 9 } 10 --CurrentAmmo.Clips; 11 } 12 CurrentAmmo.Bullets = DefaultAmmo.Bullets; 13 UE_LOG(LogBaseWeapon, Display, TEXT("---------Change Clip----------")); 14}
减少子弹时, 检查子弹数
在MakeShot中调用DecreaseAmmo, 已检查过弹药库存
ShootThemUp: Weapon/STUBaseWeapon.cpp
1// DecreaseAmmo 2 3if (CurrentAmmo.Bullets == 0) 4{ 5 UE_LOG(LogBaseWeapon, Warning, TEXT("Clips is empty")); 6 return; 7}
武器组件注册更换弹夹通知服务
添加空的处理函数
private
ShootThemUp: Components/STUWeaponComponent.h
1void OnEmptyClip();
ShootThemUp: Components/STUWeaponComponent.cpp
1void USTUWeaponComponent::OnEmptyClip() {}
创建武器后, 为武器注册服务
ShootThemUp: Components/STUWeaponComponent.cpp
1Weapon->OnClipEmpty.AddUObject(this, &USTUWeaponComponent::OnEmptyClip);
实现装弹逻辑
装弹检查时, 检查弹药库存
ShootThemUp: Components/STUWeaponComponent.cpp
1// CanReload 2 3return CurrentWeapon // 4 && !EquipAnimInProgress // 5 && !ReloadAnimInProgress // 6 && CurrentWeapon->CanReload();
添加接口, 实现更换弹夹逻辑
- 关闭连续开火定时器
- 调用武器更换弹夹逻辑
ShootThemUp: Components/STUWeaponComponent.h
private
1void ChangeClip();
ShootThemUp: Components/STUWeaponComponent.cpp
1void USTUWeaponComponent::ChangeClip() 2{ 3 if (!CanReload()) return; 4 CurrentWeapon->FireStop(); 5 CurrentWeapon->ChangeClip(); 6 ReloadAnimInProgress = true; 7 PlayAnimMontage(CurrentReloadAnimMontage); 8}
手动装弹时, 调用ChangeClip
屏蔽Reload原逻辑
ShootThemUp: Components/STUWeaponComponent.cpp
1// Reload 2 3ChangeClip();
自动装弹时, 调用ChangeClip
ShootThemUp: Components/STUWeaponComponent.cpp
1// OnEmptyClip 2 3ChangeClip();
查看
当弹夹里的子弹只剩最后一个时, 持续射击, 自动更换完弹夹后, 射击继续
- | |||
---|---|---|---|
FireStart | MakeShot > DecreaseAmmo | 子弹数减为0, 通知客户端 | OnEmptyClip中更换了弹夹并关闭了定时器 |
开启定时器 |
解决方法
- FireStart中, 先开启定时器, 再射击
ShootThemUp: Weapon/STURifleWeapon.cpp
1// FireStart 2 3GetWorldTimerManager().SetTimer(ShotTimerHandle, this, &ASTURifleWeapon::MakeShot, TimeBetweenShots, true); 4MakeShot();
- 通知弹夹为空之前, 关闭开火定时器
ShootThemUp: Weapon/STUBaseWeapon.cpp
1// DecreaseAmmo 2 3if (IsClipEmpty() && !IsAmmoEmpty()) 4{ 5 FireStop(); 6 OnClipEmpty.Broadcast(); 7}