一、添加动画
- 实现右手发射魔法粒子的动画
- 动画序列
Animation Sequence
:是预先录制的一系列骨骼动画帧,可以应用于骨骼网格体Skeletal Mesh
上。它们通常由动画师在3D建模软件(如Maya
或Blender
)中创建后导入到UE中。通常是FBX
格式。在游戏中,通过调用相应的函数播放动画序列。
- 一个动画序列包含许多个关键帧,这些关键帧规定了骨骼网格体中骨骼在特定时间点的位置、旋转和缩放信息。通过按照顺序混合这些关键帧,就能在骨骼网格体上播放骨骼动画了。
- 应用方式?
(1)角色蓝图:在角色蓝图中,通过动画蓝图Animation Blueprint
设置动画序列。
(2)动画蓝图:在动画蓝图中使用状态机State Machine
和动画图Anim Graph
将动画序列连接到角色的骨骼网格体。
- 蒙太奇
Montage
:是更为复杂和灵活的动画资产,允许将多个 动画序列和动画片段Animation Clips
组合在一起,并在特定时间点插入动画事件Animation Events
或执行动画通知Anim Notifies
。是控制动画播放的系统。
- 还可以使用动画蒙太奇来在网络游戏中复制根位移
Root Motion
动画。 - 可以切分为多个蒙太奇分段
Montage Sections
,以便在运行时,按一定逻辑以任何顺序动态播放。 - 在蒙太奇编辑器中,可以使用不同的轨道
Tracks
和段落Sections
来组织和控制动画片段。可以添加动画通知来触发特定事件(如声音效果、粒子效果等)。 - 通过角色蓝图或动画蓝图中的
Montage_Play
函数来播放蒙太奇。
动画序列和蒙太奇的区别:
(1)复杂度:动画序列比较简单,适用于播放单一的动画动作;蒙太奇更复杂,适用于组合和管理多个动画动作。
(2)灵活性:蒙太奇允许在特定时间点插入动画通知和事件,提供了更高的灵活性和控制力。
(3)用途:动画序列适用于基本的循环动画(如行走、跑步等),而蒙太奇适用于复杂的动画行为(如连招、攻击组合等)。
- 在SCharacter.cpp的
PrimaryAttack
函数实现播放动画的功能。 - 在使用
UPROPERTY
宏时加上Category
,可以使相关的变量在蓝图编辑器中显示在指定类别下。
// SurCharacter.cpp -> PrimaryAttack()
PlayAnimMontage(AttackAnim);
// SurCharacter.h
// Category指定在蓝图编辑工具中显示时的属性类别
UPROPERTY(EditAnywhere, Category = "Attack")
UAnimMontage* AttackAnim;
// 之前的投射体子类,也加上Category
UPROPERTY(EditAnywhere, Category = "Attack")
SubclassOf<AActor> ProjectileClass;
- 在UE中给AttackAnim选择动画
- 此时魔法粒子发射的位置还是之前写的角色在静止状态下右手的位置,而没有从角色抬手后的手掌中发出来。之前的计算位置:
FVector RightHandLoc = GetMesh()->GetSocketLocation("Muzzle_01");
- 解决方法:根据动画的速度在这条语句前设置相应延迟即可,也就是等0.2秒的抬手时间后,再生成粒子。所以我们利用UE中的计时器来实现这个效果
// 左键攻击
void ASurCharacter::PrimaryAttack() {
PlayAnimMontage(AttackAnim);
// 0.2s延迟后触发魔法粒子生成
GetWorldTimerManager().SetTimer(TimerHandle_PrimaryAttack, this, &ASurCharacter::PrimaryAttack_TimeElapsed, 0.18f);
}
// 原先控制魔法粒子的内容移到这个函数中
void ASurCharacter::PrimaryAttack_TimeElapsed() {
// 获取模型右手位置
FVector RightHandLoc = GetMesh()->GetSocketLocation("Muzzle_01");
// 朝向角色方向,在角色的右手位置生成
FTransform SpawnTM = FTransform(GetActorRotation(), RightHandLoc);
// 此处设置碰撞检测规则为:即使碰撞也总是生成
FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
GetWorld()->SpawnActor<AActor>(ProjectileClass, SpawnTM, SpawnParams);
}
- 定时器句柄 TimerHandle_PrimaryAttack是
FTimerHandle
类,需要在SCharacter.h文件中声明。只要定时器句柄存在,过0.2s后就会执行PrimaryAttack_TimeElapsed()
中发射粒子的代码。这样做的好处是:当角色在攻击的一瞬间死亡时,其TimerHandle_PrimaryAttack将会自动取消,那之后的动画也就不会再播放。
- 定时器句柄:是一个用来标识和管理特定定时器的对象。它允许来设置定时器、查询定时器状态、以及取消定时器。
(1)创建定时器:使用FTimerHandle
和GetWorld()->GetTimerManager()
来设置定时器。SetTimer
函数是主要的接口,它允许设置定时器的间隔时间、回调函数、是否循环等。
FTimerHandle TimerHandle;
GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &AMyClass::MyFunction, 5.0f, false);
(2)取消定时器:
GetWorld()->GetTimerManager().ClearTimer(TimerHandle);
(3)检查定时器是否有效:
bool bIsTimerActive = GetWorld()->GetTimerManager().IsTimerActive(TimerHandle);
(4)重置定时器:
GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &AMyClass::MyFunction, 5.0f, false);