六一的部落格


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




说明

AI Weapon Component

当前武器子弹耗尽时, 更换为仍有弹药的武器


查看当前NPC更换武器需求

  1. 调整武器顺序: 第一个为发射器

    BP_STUAICharacter > WeaponComponent

    拖动Index[1]到最上


  2. 修改发射器默认子弹数

    BP_STULauncherWeapon > Details > Default Ammo

    设置Clips = 2, Bullets = 1

  3. 修改步枪弹药库和伤害

    BP_STURifleWeapon > Details

    • Default Ammo

      取消勾选 Infinite, 设置Clips = 3
    • 设置DamageAmount = 0.0

查看: 射击完发射器榴弹后, 停止射击


NPC射击榴弹特效异常

在枪口处爆炸, 无移动


调试思路

NPC和玩家游戏角色的区别, 刚好在上节子弹轨迹的修改; 上层控制器类型

  • GetPlayerViewPoint由 GetTraceData 调用: 能获取到ViewLocation和ViewRotation值
  • 发射器MakeShot调用GetTraceData后, 调用 MakeHit

    打印碰撞信息: 永远发生碰撞; 怀疑MuzzleSocket变换

    输出碰撞点: 和枪口位置一致

    将轨迹终点改为根据射程计算得到的终点: 轨迹和射击方向近乎垂直

原因

MuzzleSocket变换配置存在失误; 已在 武器 > 榴弹类 更正



创建C++类

-
基类 STUWeaponComponent
路径 Components
Public
类名 STUAIWeaponComponent

调整武器基类接口的访问属性

ShootThemUp: Weapon/STUBaseWeapon.h

IsAmmoEmpty: protected > public


调整武器组件成员的访问属性

ShootThemUp: Components/STUWeaponComponent.h

  • 之前误把FireStart和FireStop声明成虚函数: 恢复FireStop
    1void FireStop();
  • STUAIWeaponComponent需要重新实现下列接口逻辑
    1virtual void FireStart();
    2virtual void NextWeapon();
  • 派生类需要访问下列成员 private > protected
    • Weapons数组
    • 当前武器指针CurrentWeapon
    • 当前武器在数组中的索引CurrentWeaponIndex
  • 派生类需要使用下列成员函数 private > protected
    • CanFire和CanEquip
    • EquipWeapon

实现STUAIWeaponComponent


覆写虚函数

public

ShootThemUp: Components/STUAIWeaponComponent.h

1virtual void FireStart() override;
2virtual void NextWeapon() override;

射击时, 若当前武器没有弹药, 尝试更换武器

ShootThemUp: Components/STUAIWeaponComponent.cpp

 1#include "Weapon/STUBaseWeapon.h"
 2
 3void USTUAIWeaponComponent::FireStart()
 4{
 5    if (!CanFire()) return;
 6
 7    if (CurrentWeapon->IsAmmoEmpty())
 8    {
 9        NextWeapon();
10    }
11    else
12    {
13        CurrentWeapon->FireStart();
14    }
15}

若存在武器弹药不为空, 切换到该武器

ShootThemUp: Components/STUAIWeaponComponent.cpp

 1void USTUAIWeaponComponent::NextWeapon()
 2{
 3    if (!CanEquip()) return;
 4
 5    int32 NextIndex = (CurrentWeaponIndex + 1) % Weapons.Num();
 6    while (NextIndex != CurrentWeaponIndex)
 7    {
 8        if (!Weapons[NextIndex]->IsAmmoEmpty()) break;
 9        NextIndex = (NextIndex + 1) % Weapons.Num();
10    }
11
12    if (NextIndex != CurrentWeaponIndex)
13    {
14        CurrentWeaponIndex = NextIndex;
15        EquipWeapon(CurrentWeaponIndex);
16    }
17}

AICharacter使用STUAIWeaponComponent

参考STUBaseCharacter使用STUCharacterMovementComponent

ShootThemUp: Player/STUBaseCharacter.cpp

ShootThemUp: AI/STUAICharacter.cpp

1#include "Components/STUAIWeaponComponent.h"
2
3ASTUAICharacter::ASTUAICharacter(const FObjectInitializer &ObjInit)
4    : Super(ObjInit.SetDefaultSubobjectClass<USTUAIWeaponComponent>("WeaponComponent"))
5{
6    // ...
7}

查看

榴弹用完后自动更换武器, 步枪子弹用完后无法射击


NPC自行更换武器



说明

AI Weapon Component

当前武器子弹耗尽时, 更换为仍有弹药的武器


查看当前NPC更换武器需求

  1. 调整武器顺序: 第一个为发射器

    BP_STUAICharacter > WeaponComponent

    拖动Index[1]到最上


  2. 修改发射器默认子弹数

    BP_STULauncherWeapon > Details > Default Ammo

    设置Clips = 2, Bullets = 1

  3. 修改步枪弹药库和伤害

    BP_STURifleWeapon > Details

    • Default Ammo

      取消勾选 Infinite, 设置Clips = 3
    • 设置DamageAmount = 0.0

查看: 射击完发射器榴弹后, 停止射击


NPC射击榴弹特效异常

在枪口处爆炸, 无移动


调试思路

NPC和玩家游戏角色的区别, 刚好在上节子弹轨迹的修改; 上层控制器类型

  • GetPlayerViewPoint由 GetTraceData 调用: 能获取到ViewLocation和ViewRotation值
  • 发射器MakeShot调用GetTraceData后, 调用 MakeHit

    打印碰撞信息: 永远发生碰撞; 怀疑MuzzleSocket变换

    输出碰撞点: 和枪口位置一致

    将轨迹终点改为根据射程计算得到的终点: 轨迹和射击方向近乎垂直

原因

MuzzleSocket变换配置存在失误; 已在 武器 > 榴弹类 更正



创建C++类

-
基类 STUWeaponComponent
路径 Components
Public
类名 STUAIWeaponComponent

调整武器基类接口的访问属性

ShootThemUp: Weapon/STUBaseWeapon.h

IsAmmoEmpty: protected > public


调整武器组件成员的访问属性

ShootThemUp: Components/STUWeaponComponent.h

  • 之前误把FireStart和FireStop声明成虚函数: 恢复FireStop
    1void FireStop();
  • STUAIWeaponComponent需要重新实现下列接口逻辑
    1virtual void FireStart();
    2virtual void NextWeapon();
  • 派生类需要访问下列成员 private > protected
    • Weapons数组
    • 当前武器指针CurrentWeapon
    • 当前武器在数组中的索引CurrentWeaponIndex
  • 派生类需要使用下列成员函数 private > protected
    • CanFire和CanEquip
    • EquipWeapon

实现STUAIWeaponComponent


覆写虚函数

public

ShootThemUp: Components/STUAIWeaponComponent.h

1virtual void FireStart() override;
2virtual void NextWeapon() override;

射击时, 若当前武器没有弹药, 尝试更换武器

ShootThemUp: Components/STUAIWeaponComponent.cpp

 1#include "Weapon/STUBaseWeapon.h"
 2
 3void USTUAIWeaponComponent::FireStart()
 4{
 5    if (!CanFire()) return;
 6
 7    if (CurrentWeapon->IsAmmoEmpty())
 8    {
 9        NextWeapon();
10    }
11    else
12    {
13        CurrentWeapon->FireStart();
14    }
15}

若存在武器弹药不为空, 切换到该武器

ShootThemUp: Components/STUAIWeaponComponent.cpp

 1void USTUAIWeaponComponent::NextWeapon()
 2{
 3    if (!CanEquip()) return;
 4
 5    int32 NextIndex = (CurrentWeaponIndex + 1) % Weapons.Num();
 6    while (NextIndex != CurrentWeaponIndex)
 7    {
 8        if (!Weapons[NextIndex]->IsAmmoEmpty()) break;
 9        NextIndex = (NextIndex + 1) % Weapons.Num();
10    }
11
12    if (NextIndex != CurrentWeaponIndex)
13    {
14        CurrentWeaponIndex = NextIndex;
15        EquipWeapon(CurrentWeaponIndex);
16    }
17}

AICharacter使用STUAIWeaponComponent

参考STUBaseCharacter使用STUCharacterMovementComponent

ShootThemUp: Player/STUBaseCharacter.cpp

ShootThemUp: AI/STUAICharacter.cpp

1#include "Components/STUAIWeaponComponent.h"
2
3ASTUAICharacter::ASTUAICharacter(const FObjectInitializer &ObjInit)
4    : Super(ObjInit.SetDefaultSubobjectClass<USTUAIWeaponComponent>("WeaponComponent"))
5{
6    // ...
7}

查看

榴弹用完后自动更换武器, 步枪子弹用完后无法射击