为装弹动画剪辑添加通知
2023年9月7日 2024年1月11日
说明
播放动画时, 不允许其他操作, 使用动画通知 AnimNotify
实现
概览
- 为更换武器和装弹创建动画通知基类
- 将动画通知逻辑移动到STUAnimNotify, 使STUEquipFinishedAnimNotify派生自STUAnimNotify
- 在装弹动画中添加结束事件, 注册处理函数
- 手动装弹时检查, 完善开火和更换武器检查
创建AnimNotify派生类
创建STUAnimNotify
- | |
---|---|
基类 | AnimNotify |
路径 | Animations |
属性 | Public |
创建STUReloadFinishedAnimNotify
- | |
---|---|
基类 | STUAnimNOtify |
路径 | Animations |
属性 | Public |
把动画通知逻辑从STUEquipFinishedAnimNotify移动到STUAnimNotify
实现STUAnimNotify
- 定义委托类型
ShootThemUp: Animations/STUAnimNotify.h
1DECLARE_MULTICAST_DELEGATE_OneParam(FOnNotifiedSignature, USkeletalMeshComponent*);
- 添加数据成员
public
ShootThemUp: Animations/STUAnimNotify.h
1FOnNotifiedSignature OnNotified;
- 覆写虚函数
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
- 派生自STUAnimNotify, 修改头文件
ShootThemUp: Animations/STUEquipFinishedAnimNotify.h
1// #include "Animation/AnimNotifies/AnimNotify.h" 2#include "Animations/STUAnimNotify.h" 3 4class SHOOTTHEMUP_API USTUEquipFinishedAnimNotify : public STUAnimNotify
- 屏蔽数据成员OnNotified
ShootThemUp: Animations/STUEquipFinishedAnimNotify.h
- 屏蔽函数成员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}