写在前面
现在,我们的角色已经可以自由移动了,但是我们希望角色可以在我们按下控制键的时候有相应的动作。
我还记得之前在写网页端的弹框变化时,我们需要根据用户的选择步骤来变换弹框的样式和显示的内容,逻辑很简单,设定多个状态参数
对应不同的弹框样式
,然后在某个契机
改变我们的状态参数,让相应的弹框样式显示出来即可。
UE5的动画的原理也是类似这样,只不过我们从简单的参数和静态的css样式变成了多个参数和动漫序列。设置state machine
(离散性状态,如idle/jump)和blend space
(连续性状态,比如从慢跑过渡到快跑,比如从向右跑过渡到向左跑),在不同的状态,我们播放相应的animation。
接下来我们要开始实现角色的基本移动动画,有了这些动画后,我们就可以用一个移动的小人来模拟玩家测试游戏了。
在C++类中建立状态
建立一个新的animinstance
类,该类可以作为AnimationBluePrint的基类来使用。
Cpp
// header
class BLASTER_API UBlasterAnimInstance : public UAnimInstance
{
GENERATED_BODY()
public:
// 在动画刚建立时调用
virtual void NativeInitializeAnimation() override;
// 在更新动画时调用,相当于Tick
virtual void NativeUpdateAnimation(float DeltaSeconds) override;
private:
UPROPERTY(BlueprintReadOnly, Category = Character, meta = (AllowPrivateAccess = "true")) // 因为这是private的,所以必须写上AllowPrivateAccess才能在蓝图中访问
class ABlasterCharacter *BlasterCharacter;
UPROPERTY(BlueprintReadOnly, Category = Character, meta = (AllowPrivateAccess = "true"))
float Speed; // 根据速度,来运动的快慢
UPROPERTY(BlueprintReadOnly, Category = Character, meta = (AllowPrivateAccess = "true"))
bool bIsInAir; // 是否在空中,用来判断是否跳跃
UPROPERTY(BlueprintReadOnly, Category = Character, meta = (AllowPrivateAccess = "true"))
bool bIsAccelerating; // 是否在加速
};
Cpp
void UBlasterAnimInstance::NativeInitializeAnimation()
{
Super::NativeInitializeAnimation();
BlasterCharacter = Cast<ABlasterCharacter>(TryGetPawnOwner());
}
void UBlasterAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
if (BlasterCharacter)
{
BlasterCharacter = Cast<ABlasterCharacter>(TryGetPawnOwner());
}
if (!BlasterCharacter)
{
return;
}
// 获取速度
auto charVelocity = BlasterCharacter->GetVelocity();
charVelocity.Z = 0; // 只要平地上的运动
Speed = charVelocity.Size(); // 获取速度
bIsInAir = BlasterCharacter->GetMovementComponent()->IsFalling(); // 是否在下坠 以此判断是否在空中
bIsAccelerating = BlasterCharacter->GetCharacterMovement()->GetCurrentAcceleration().Size() > 0 ? true : false; // 并非是物理学上的加速度,而是指玩家的输入
}
基于C++类建立动画蓝图
首先,在要建立的地方单击右键,选择动画蓝图, 建立动画蓝图。
在这里我们需要选择一个父类(选择我们自己刚刚已经写好的)和一个skeleton(你的动画绑的是哪个那就用哪个,注意和skeleton mesh文件区别)。
接下来我们进入动画蓝图编辑界面的AnimeGraph
tab,右键,建立第一个状态机来处理角色的常规动画。
点击进入Unequiped状态机,建立其以下状态,状态的数量大体和你有多少动画序列成正比。以模拟角色在普通状态下的动画转变。
观察上图,每个状态
节点用同心矩形
来表示,在上面我们定义动画的展示;每个度
定义了一个状态改变的行为
(往往是一个bool的检查)。总体而言,整个状态机是一个有向图,每个状态之间只要你想,就可以互相转换。
首先我们得从双脚着地
到双脚离体
,很简单,判断是否IsInAir
中即可。
之后我们从Jump
直接过渡到下坠
状态。
勾上这个选项后,代表Jump
的动画放完后,直接进入Falling
开始播放Falling
动画.
那么接下来,我们要着陆了,那就简单了,直接判断是否在空中即可。
因为我们的着陆动画只播放一次,因此我们记得把loop给取消。
接着,我们使用TimeRemainingRatio <= 0.1
作为触发条件,确保在着陆动画的最后10%的时间内,才开始准备过渡到idle状态。这通常是动画的"安静期"或"收尾动作",这样可以避免中断动画的关键部分,使得动作看起来不自然或突兀。
接着,我们给每个state加上合适的动画。
然后,对于idle状态,因为对应着原地
,走
,小跑
涉及到了多个状态之间的平滑过渡,所以我们要将这些动画blend
在一起,所以会用到混合空间
。因为我们只想通过速度来控制跑步,因此,我们只需要1D。
首先,我们先看这个过度条组件: 我们可以在不同的过度点添加动画节点。按住ctrl
拖动X
查看过度。
接着我们可以通过设置Horizontal Axis的设置来改变这个进度条属性。
在完成blend space之后,我们发现ue非常智能得替我们创建了多个动画之间的补间动画,动画之间变得很自然。(^_^) 简直是加强版Live2D。
好了,这样一来我们的idle state也有着落了。
注意
- 如果发现角色在落地时缩小或消失,可能是这个问题:
- 暂未解决的问题,角色下落会滑翔,但是如果在跳跃时没有按住按钮就不会滑翔。