角色动画蓝图 Animation Blueprint

写在前面

现在,我们的角色已经可以自由移动了,但是我们希望角色可以在我们按下控制键的时候有相应的动作。

我还记得之前在写网页端的弹框变化时,我们需要根据用户的选择步骤来变换弹框的样式和显示的内容,逻辑很简单,设定多个状态参数对应不同的弹框样式,然后在某个契机改变我们的状态参数,让相应的弹框样式显示出来即可。

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文件区别)。

接下来我们进入动画蓝图编辑界面的AnimeGraphtab,右键,建立第一个状态机来处理角色的常规动画。

点击进入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也有着落了。

注意

  • 如果发现角色在落地时缩小或消失,可能是这个问题:

Character shrinks and disappears when jumping - Development / Character & Animation - Epic Developer Community Forums (unrealengine.com)

  • 暂未解决的问题,角色下落会滑翔,但是如果在跳跃时没有按住按钮就不会滑翔。
相关推荐
Clarify5 天前
一种增量式的状态同步方案
后端·游戏开发
foenix669 天前
Unreal的Audio::IAudioCaptureStream在Android中录制数据异常
android·c#·unreal engine
异次元的归来9 天前
UE5的TRS矩阵
线性代数·矩阵·ue5·游戏引擎·unreal engine
Thomas_YXQ12 天前
Unity3D项目为什么要使用FairyGUI
开发语言·unity·游戏引擎·unity3d·游戏开发
DoomGT14 天前
Design - 个人设计的一些科幻场景
游戏引擎·虚幻·虚幻引擎·unreal engine
Raysen16 天前
GridLayout玩出花系列-使用Android原生GridLayout控件打造方块消除小游戏
android·游戏开发
kissSimple23 天前
给UE5优化一丢丢编辑器性能
ue5·虚幻引擎·unreal engine·unreal engine 5
Thomas_YXQ1 个月前
Unity3D ngui和ugui区别与优缺点详解
服务器·游戏·unity·unity3d·游戏开发
刘好念1 个月前
[UE5学习] 一、使用源代码安装UE5.4
ue5·游戏开发
懷淰メ1 个月前
PyQt飞机大战游戏(附下载地址)
开发语言·python·qt·游戏·pyqt·游戏开发·pyqt5