六一的部落格


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




说明

  1. 已在弹夹子弹耗尽时实现自动装弹逻辑
  2. 现在实现手动装弹的第一步, 播放装弹动画
  3. 步枪和发射器各有一个装弹动画, 使用动画剪辑实现

概览

  • 创建两个动画剪辑资产, 并设置SlotName
  • 绑定手动装弹键位
  • 将武器信息封装到数据结构
  • 更换武器时, 更新对应的装弹动画

创建动画剪辑资产

  1. 为装弹动画绑定骨骼HeroTPP_Skeleton, 创建对应的动画剪辑资产, 保存到Player/Animations

    -
    Launcher_Reload AM_Launcher_Reload
    Reload AM_Reload


  2. 设置动画剪辑的SlotName, 选择UpperBody




绑定装弹键位

项目设置 > Engine > Input

-
类型 Action Mappings
函数描述 Reload
键位 R



搭建手动装弹框架


添加空的Reload函数

ShootThemUp: Components/STUWeaponComponent.h

public

1void Reload();

ShootThemUp: Components/STUWeaponComponent.cpp

1void USTUWeaponComponent::Reload()
2{
3    PlayAnimMontage(CurrentReloadAnimMontage);
4}

绑定函数描述和回调函数

ShootThemUp: Player/STUBaseCharacter.cpp

1// SetupPlayerInputComponent
2PlayerInputComponent->BindAction("Reload", IE_Pressed, WeaponComponent, &USTUWeaponComponent::Reload);           

将武器信息封装到数据结构

当前, 不同武器有各自的武器类属性, 结合装弹动画, 定义存放武器信息的数据结构


定义数据结构存放武器信息

ShootThemUp: Components/STUWeaponComponent.h

 1USTRUCT(BlueprintType)
 2struct FWeaponData
 3{
 4    GENERATED_USTRUCT_BODY()
 5    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Weapon")
 6    TSubclassOf<ASTUBaseWeapon> WeaponClass;
 7
 8    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Weapon")
 9    UAnimMontage *ReloadAnimMontage;
10};

在武器组件类添加数组成员, 存放武器信息

protected

ShootThemUp: Components/STUWeaponComponent.h

1UPROPERTY(EditDefaultsOnly, Category = "Weapon")
2TArray<FWeaponData> WeaponData;

屏蔽武器类属性

ShootThemUp: Components/STUWeaponComponent.h


创建武器时, 依据数组信息

注意: 若创建武器失败, 继续创建其他武器

ShootThemUp: Components/STUWeaponComponent.cpp

1// SpawnWeapons
2 for (auto OneWeaponData : WeaponData)
3 {
4     auto Weapon = GetWorld()->SpawnActor<ASTUBaseWeapon>(OneWeaponData.WeaponClass);
5     if (!Weapon) continue;
6     Weapons.Add(Weapon);
7     Weapon->SetOwner(Character);
8     AttachWeaponToSocket(Weapon, Character->GetMesh(), WeaponArmorySocketName);
9 }

添加属性, 指向当前装弹动画

private

经常需要播放装弹动画

ShootThemUp: Components/STUWeaponComponent.h

1UPROPERTY()
2UAnimMontage *CurrentReloadAnimMontage = nullptr;

更换武器时, 更新装弹动画

EquipWeapon

ShootThemUp: Components/STUWeaponComponent.cpp


进入时检查WeaponIndex

1if (WeaponIndex < 0 || WeaponIndex >= Weapons.Num())
2{
3    UE_LOG(LogWeaponComponent, Warning, TEXT("Invalid weapon index"));
4    return;
5}

不使用武器标号获取动画剪辑

  1. 创建武器时, 根据WeaponData元素顺序
  2. 存在武器创建失败的情况, 后续可能需要对武器进行排序
1// CurrentReloadAnimMontage = WeaponData[WeaponIndex].ReloadAnimMontage;           

根据武器类型, 查找对应的武器信息

使用lambda表达式实现查找谓语

  • 对调用运算符进行重载
  • 使用lambda表达式实现一元谓语, 捕获引用, 比对武器类型, 返回true或false
  • 若匹配元素个数为0或大于1, 查找函数返回nullptr
1const auto CurrentWeaponData = WeaponData.FindByPredicate([&](const FWeaponData &Data){ // 
2    return Data.WeaponClass == CurrentWeapon->GetClass();                               //
3});

设置当前武器的装弹动画剪辑

1CurrentReloadAnimMontage = CurrentWeaponData ? CurrentWeaponData->ReloadAnimMontage : nullptr;

设置游戏角色的WeaponData数组

打开BP_STUBaseCharacter, 选中WeaponComponent, 去到Details > Weapon > WeaponData


装弹动画



说明

  1. 已在弹夹子弹耗尽时实现自动装弹逻辑
  2. 现在实现手动装弹的第一步, 播放装弹动画
  3. 步枪和发射器各有一个装弹动画, 使用动画剪辑实现

概览

  • 创建两个动画剪辑资产, 并设置SlotName
  • 绑定手动装弹键位
  • 将武器信息封装到数据结构
  • 更换武器时, 更新对应的装弹动画

创建动画剪辑资产

  1. 为装弹动画绑定骨骼HeroTPP_Skeleton, 创建对应的动画剪辑资产, 保存到Player/Animations

    -
    Launcher_Reload AM_Launcher_Reload
    Reload AM_Reload


  2. 设置动画剪辑的SlotName, 选择UpperBody




绑定装弹键位

项目设置 > Engine > Input

-
类型 Action Mappings
函数描述 Reload
键位 R



搭建手动装弹框架


添加空的Reload函数

ShootThemUp: Components/STUWeaponComponent.h

public

1void Reload();

ShootThemUp: Components/STUWeaponComponent.cpp

1void USTUWeaponComponent::Reload()
2{
3    PlayAnimMontage(CurrentReloadAnimMontage);
4}

绑定函数描述和回调函数

ShootThemUp: Player/STUBaseCharacter.cpp

1// SetupPlayerInputComponent
2PlayerInputComponent->BindAction("Reload", IE_Pressed, WeaponComponent, &USTUWeaponComponent::Reload);           

将武器信息封装到数据结构

当前, 不同武器有各自的武器类属性, 结合装弹动画, 定义存放武器信息的数据结构


定义数据结构存放武器信息

ShootThemUp: Components/STUWeaponComponent.h

 1USTRUCT(BlueprintType)
 2struct FWeaponData
 3{
 4    GENERATED_USTRUCT_BODY()
 5    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Weapon")
 6    TSubclassOf<ASTUBaseWeapon> WeaponClass;
 7
 8    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Weapon")
 9    UAnimMontage *ReloadAnimMontage;
10};

在武器组件类添加数组成员, 存放武器信息

protected

ShootThemUp: Components/STUWeaponComponent.h

1UPROPERTY(EditDefaultsOnly, Category = "Weapon")
2TArray<FWeaponData> WeaponData;

屏蔽武器类属性

ShootThemUp: Components/STUWeaponComponent.h


创建武器时, 依据数组信息

注意: 若创建武器失败, 继续创建其他武器

ShootThemUp: Components/STUWeaponComponent.cpp

1// SpawnWeapons
2 for (auto OneWeaponData : WeaponData)
3 {
4     auto Weapon = GetWorld()->SpawnActor<ASTUBaseWeapon>(OneWeaponData.WeaponClass);
5     if (!Weapon) continue;
6     Weapons.Add(Weapon);
7     Weapon->SetOwner(Character);
8     AttachWeaponToSocket(Weapon, Character->GetMesh(), WeaponArmorySocketName);
9 }

添加属性, 指向当前装弹动画

private

经常需要播放装弹动画

ShootThemUp: Components/STUWeaponComponent.h

1UPROPERTY()
2UAnimMontage *CurrentReloadAnimMontage = nullptr;

更换武器时, 更新装弹动画

EquipWeapon

ShootThemUp: Components/STUWeaponComponent.cpp


进入时检查WeaponIndex

1if (WeaponIndex < 0 || WeaponIndex >= Weapons.Num())
2{
3    UE_LOG(LogWeaponComponent, Warning, TEXT("Invalid weapon index"));
4    return;
5}

不使用武器标号获取动画剪辑

  1. 创建武器时, 根据WeaponData元素顺序
  2. 存在武器创建失败的情况, 后续可能需要对武器进行排序
1// CurrentReloadAnimMontage = WeaponData[WeaponIndex].ReloadAnimMontage;           

根据武器类型, 查找对应的武器信息

使用lambda表达式实现查找谓语

  • 对调用运算符进行重载
  • 使用lambda表达式实现一元谓语, 捕获引用, 比对武器类型, 返回true或false
  • 若匹配元素个数为0或大于1, 查找函数返回nullptr
1const auto CurrentWeaponData = WeaponData.FindByPredicate([&](const FWeaponData &Data){ // 
2    return Data.WeaponClass == CurrentWeapon->GetClass();                               //
3});

设置当前武器的装弹动画剪辑

1CurrentReloadAnimMontage = CurrentWeaponData ? CurrentWeaponData->ReloadAnimMontage : nullptr;

设置游戏角色的WeaponData数组

打开BP_STUBaseCharacter, 选中WeaponComponent, 去到Details > Weapon > WeaponData