六一的部落格


关关难过关关过,前路漫漫亦灿灿。




说明

  1. 自动装弹时播放动画
  2. 手动装弹时更新弹药库存

概览

  • 定义委托类型, 用于自动装弹
  • 提取封装装弹逻辑, 供手动/自动装弹时使用

在武器类定义委托, 需要更换弹夹时进行通知


定义委托, 在弹药用完时行通知客户端

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();

添加接口, 实现更换弹夹逻辑

  1. 关闭连续开火定时器
  2. 调用武器更换弹夹逻辑

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中更换了弹夹并关闭了定时器
开启定时器

解决方法

  1. FireStart中, 先开启定时器, 再射击

    ShootThemUp: Weapon/STURifleWeapon.cpp
    1// FireStart
    2
    3GetWorldTimerManager().SetTimer(ShotTimerHandle, this, &ASTURifleWeapon::MakeShot, TimeBetweenShots, true);
    4MakeShot();           
    
  2. 通知弹夹为空之前, 关闭开火定时器

    ShootThemUp: Weapon/STUBaseWeapon.cpp
    1// DecreaseAmmo
    2
    3if (IsClipEmpty() && !IsAmmoEmpty())
    4{
    5    FireStop();
    6    OnClipEmpty.Broadcast();
    7}

完善装弹逻辑



说明

  1. 自动装弹时播放动画
  2. 手动装弹时更新弹药库存

概览

  • 定义委托类型, 用于自动装弹
  • 提取封装装弹逻辑, 供手动/自动装弹时使用

在武器类定义委托, 需要更换弹夹时进行通知


定义委托, 在弹药用完时行通知客户端

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();

添加接口, 实现更换弹夹逻辑

  1. 关闭连续开火定时器
  2. 调用武器更换弹夹逻辑

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中更换了弹夹并关闭了定时器
开启定时器

解决方法

  1. FireStart中, 先开启定时器, 再射击

    ShootThemUp: Weapon/STURifleWeapon.cpp
    1// FireStart
    2
    3GetWorldTimerManager().SetTimer(ShotTimerHandle, this, &ASTURifleWeapon::MakeShot, TimeBetweenShots, true);
    4MakeShot();           
    
  2. 通知弹夹为空之前, 关闭开火定时器

    ShootThemUp: Weapon/STUBaseWeapon.cpp
    1// DecreaseAmmo
    2
    3if (IsClipEmpty() && !IsAmmoEmpty())
    4{
    5    FireStop();
    6    OnClipEmpty.Broadcast();
    7}