六一的部落格


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




说明

播放动画时, 不允许其他操作, 使用动画通知 AnimNotify 实现


概览

  • 为更换武器和装弹创建动画通知基类
  • 将动画通知逻辑移动到STUAnimNotify, 使STUEquipFinishedAnimNotify派生自STUAnimNotify
  • 在装弹动画中添加结束事件, 注册处理函数
  • 手动装弹时检查, 完善开火和更换武器检查

创建AnimNotify派生类



创建STUAnimNotify

-
基类 AnimNotify
路径 Animations
属性 Public



创建STUReloadFinishedAnimNotify

-
基类 STUAnimNOtify
路径 Animations
属性 Public



把动画通知逻辑从STUEquipFinishedAnimNotify移动到STUAnimNotify


实现STUAnimNotify

  1. 定义委托类型

    ShootThemUp: Animations/STUAnimNotify.h
    1DECLARE_MULTICAST_DELEGATE_OneParam(FOnNotifiedSignature, USkeletalMeshComponent*);
  2. 添加数据成员

    public

    ShootThemUp: Animations/STUAnimNotify.h
    1FOnNotifiedSignature OnNotified;           
    
  3. 覆写虚函数

    public

    ShootThemUp: Animations/STUAnimNotify.h
    1virtual void Notify(USkeletalMeshComponent *MeshComp, UAnimSequenceBase *Animation, const FAnimNotifyEventReference& EventReference) override;
    ShootThemUp: Animations/STUAnimNotify.cpp
    1void USTUAnimNotify::Notify(USkeletalMeshComponent *MeshComp, UAnimSequenceBase *Animation, const FAnimNotifyEventReference& EventReference)
    2{
    3    OnNotified.Broadcast(MeshComp);
    4    Super::Notify(MeshComp, Animation, EventReference);
    5}

修改STUEquipFinishedAnimNotify

  1. 派生自STUAnimNotify, 修改头文件

    ShootThemUp: Animations/STUEquipFinishedAnimNotify.h
    1// #include "Animation/AnimNotifies/AnimNotify.h"
    2#include "Animations/STUAnimNotify.h"
    3
    4class SHOOTTHEMUP_API USTUEquipFinishedAnimNotify : public STUAnimNotify
  2. 屏蔽数据成员OnNotified

    ShootThemUp: Animations/STUEquipFinishedAnimNotify.h
  3. 屏蔽函数成员Notify

    ShootThemUp: Animations/STUEquipFinishedAnimNotify.h

    ShootThemUp: Animations/STUEquipFinishedAnimNotify.cpp

实现模板函数, 给定动画剪辑, 查找指定类型的通知事件

private

ShootThemUp: Components/STUWeaponComponent.h

 1#include "Animation/AnimSequenceBase.h"
 2
 3template<typename T>
 4T* FindNotifyByClass(UAnimSequenceBase *Animation)
 5{
 6    if (!Animation) return nullptr;
 7
 8    const auto NotifyEvents = Animation->Notifies;
 9    for (auto NotifyEvent : NotifyEvents)
10    {
11        auto AnimNotify = Cast<T>(NotifyEvent.Notify);
12        if (AnimNotify)
13        {
14            return AnimNotify;
15        }
16    }
17    return nullptr;
18}

修改InitAnimations中查找更换武器结束事件的方式

ShootThemUp: Components/STUWeaponComponent.cpp

1auto EquipFinishedNotify = FindNotifyByClass<USTUEquipFinishedAnimNotify>(EquipAnimMontage);
2if (EquipFinishedNotify)
3{
4    EquipFinishedNotify->OnNotified.AddUObject(this, &USTUWeaponComponent::OnEquipFinished);
5}

搭建装弹动画结束通知框架


在装弹动画剪辑中添加通知事件




定义空的回调函数

private

ShootThemUp: Components/STUWeaponComponent.h

1void OnReloadFinished(USkeletalMeshComponent *MeshComp);

ShootThemUp: Components/STUWeaponComponent.cpp

1void USTUWeaponComponent::OnReloadFinished(USkeletalMeshComponent *MeshComp) { }

为装弹动画结束事件注册处理函数

ShootThemUp: Components/STUWeaponComponent.cpp

 1#include "Animations/STUReloadFinishedAnimNotify.h"
 2
 3for (auto OneWeaponData : WeaponData)
 4{
 5    auto ReloadFinishedNotify = FindNotifyByClass<USTUReloadFinishedAnimNotify>(OneWeaponData.ReloadAnimMontage);
 6    if (ReloadFinishedNotify)
 7    {
 8        ReloadFinishedNotify->OnNotified.AddUObject(this, &USTUWeaponComponent::OnReloadFinished);
 9    }
10}

手动装弹时进行检查


添加标志位

private

ShootThemUp: Components/STUWeaponComponent.h

1bool ReloadAnimInProgress = false;

实现检查接口

private

ShootThemUp: Components/STUWeaponComponent.h

1bool CanReload() const;        

ShootThemUp: Components/STUWeaponComponent.cpp

1bool USTUWeaponComponent::CanReload() const
2{
3    return CurrentWeapon && !EquipAnimInProgress && !ReloadAnimInProgress;
4}

播放装弹动画前进行检查, 设置标志位

ShootThemUp: Components/STUWeaponComponent.cpp

1// Reload
2
3if (!CanReload()) return;
4ReloadAnimInProgress = true;

修改开火检查

ShootThemUp: Components/STUWeaponComponent.cpp

1// CanFire
2return CurrentWeapon && !EquipAnimInProgress && !ReloadAnimInProgress;

修改更换武器检查

ShootThemUp: Components/STUWeaponComponent.cpp

1// CanEquip
2return !EquipAnimInProgress && !ReloadAnimInProgress;

实现回调函数

ShootThemUp: Components/STUWeaponComponent.cpp

1void USTUWeaponComponent::OnReloadFinished(USkeletalMeshComponent *MeshComp)
2{
3    ACharacter *Character = Cast<ACharacter>(GetOwner());
4    if (!Character || (Character->GetMesh() != MeshComp)) return;
5
6    ReloadAnimInProgress = false;    
7}

为装弹动画剪辑添加通知



说明

播放动画时, 不允许其他操作, 使用动画通知 AnimNotify 实现


概览

  • 为更换武器和装弹创建动画通知基类
  • 将动画通知逻辑移动到STUAnimNotify, 使STUEquipFinishedAnimNotify派生自STUAnimNotify
  • 在装弹动画中添加结束事件, 注册处理函数
  • 手动装弹时检查, 完善开火和更换武器检查

创建AnimNotify派生类



创建STUAnimNotify

-
基类 AnimNotify
路径 Animations
属性 Public



创建STUReloadFinishedAnimNotify

-
基类 STUAnimNOtify
路径 Animations
属性 Public



把动画通知逻辑从STUEquipFinishedAnimNotify移动到STUAnimNotify


实现STUAnimNotify

  1. 定义委托类型

    ShootThemUp: Animations/STUAnimNotify.h
    1DECLARE_MULTICAST_DELEGATE_OneParam(FOnNotifiedSignature, USkeletalMeshComponent*);
  2. 添加数据成员

    public

    ShootThemUp: Animations/STUAnimNotify.h
    1FOnNotifiedSignature OnNotified;           
    
  3. 覆写虚函数

    public

    ShootThemUp: Animations/STUAnimNotify.h
    1virtual void Notify(USkeletalMeshComponent *MeshComp, UAnimSequenceBase *Animation, const FAnimNotifyEventReference& EventReference) override;
    ShootThemUp: Animations/STUAnimNotify.cpp
    1void USTUAnimNotify::Notify(USkeletalMeshComponent *MeshComp, UAnimSequenceBase *Animation, const FAnimNotifyEventReference& EventReference)
    2{
    3    OnNotified.Broadcast(MeshComp);
    4    Super::Notify(MeshComp, Animation, EventReference);
    5}

修改STUEquipFinishedAnimNotify

  1. 派生自STUAnimNotify, 修改头文件

    ShootThemUp: Animations/STUEquipFinishedAnimNotify.h
    1// #include "Animation/AnimNotifies/AnimNotify.h"
    2#include "Animations/STUAnimNotify.h"
    3
    4class SHOOTTHEMUP_API USTUEquipFinishedAnimNotify : public STUAnimNotify
  2. 屏蔽数据成员OnNotified

    ShootThemUp: Animations/STUEquipFinishedAnimNotify.h
  3. 屏蔽函数成员Notify

    ShootThemUp: Animations/STUEquipFinishedAnimNotify.h

    ShootThemUp: Animations/STUEquipFinishedAnimNotify.cpp

实现模板函数, 给定动画剪辑, 查找指定类型的通知事件

private

ShootThemUp: Components/STUWeaponComponent.h

 1#include "Animation/AnimSequenceBase.h"
 2
 3template<typename T>
 4T* FindNotifyByClass(UAnimSequenceBase *Animation)
 5{
 6    if (!Animation) return nullptr;
 7
 8    const auto NotifyEvents = Animation->Notifies;
 9    for (auto NotifyEvent : NotifyEvents)
10    {
11        auto AnimNotify = Cast<T>(NotifyEvent.Notify);
12        if (AnimNotify)
13        {
14            return AnimNotify;
15        }
16    }
17    return nullptr;
18}

修改InitAnimations中查找更换武器结束事件的方式

ShootThemUp: Components/STUWeaponComponent.cpp

1auto EquipFinishedNotify = FindNotifyByClass<USTUEquipFinishedAnimNotify>(EquipAnimMontage);
2if (EquipFinishedNotify)
3{
4    EquipFinishedNotify->OnNotified.AddUObject(this, &USTUWeaponComponent::OnEquipFinished);
5}

搭建装弹动画结束通知框架


在装弹动画剪辑中添加通知事件




定义空的回调函数

private

ShootThemUp: Components/STUWeaponComponent.h

1void OnReloadFinished(USkeletalMeshComponent *MeshComp);

ShootThemUp: Components/STUWeaponComponent.cpp

1void USTUWeaponComponent::OnReloadFinished(USkeletalMeshComponent *MeshComp) { }

为装弹动画结束事件注册处理函数

ShootThemUp: Components/STUWeaponComponent.cpp

 1#include "Animations/STUReloadFinishedAnimNotify.h"
 2
 3for (auto OneWeaponData : WeaponData)
 4{
 5    auto ReloadFinishedNotify = FindNotifyByClass<USTUReloadFinishedAnimNotify>(OneWeaponData.ReloadAnimMontage);
 6    if (ReloadFinishedNotify)
 7    {
 8        ReloadFinishedNotify->OnNotified.AddUObject(this, &USTUWeaponComponent::OnReloadFinished);
 9    }
10}

手动装弹时进行检查


添加标志位

private

ShootThemUp: Components/STUWeaponComponent.h

1bool ReloadAnimInProgress = false;

实现检查接口

private

ShootThemUp: Components/STUWeaponComponent.h

1bool CanReload() const;        

ShootThemUp: Components/STUWeaponComponent.cpp

1bool USTUWeaponComponent::CanReload() const
2{
3    return CurrentWeapon && !EquipAnimInProgress && !ReloadAnimInProgress;
4}

播放装弹动画前进行检查, 设置标志位

ShootThemUp: Components/STUWeaponComponent.cpp

1// Reload
2
3if (!CanReload()) return;
4ReloadAnimInProgress = true;

修改开火检查

ShootThemUp: Components/STUWeaponComponent.cpp

1// CanFire
2return CurrentWeapon && !EquipAnimInProgress && !ReloadAnimInProgress;

修改更换武器检查

ShootThemUp: Components/STUWeaponComponent.cpp

1// CanEquip
2return !EquipAnimInProgress && !ReloadAnimInProgress;

实现回调函数

ShootThemUp: Components/STUWeaponComponent.cpp

1void USTUWeaponComponent::OnReloadFinished(USkeletalMeshComponent *MeshComp)
2{
3    ACharacter *Character = Cast<ACharacter>(GetOwner());
4    if (!Character || (Character->GetMesh() != MeshComp)) return;
5
6    ReloadAnimInProgress = false;    
7}