角色动画蓝图 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)

  • 暂未解决的问题,角色下落会滑翔,但是如果在跳跃时没有按住按钮就不会滑翔。
相关推荐
Thomas_YXQ4 天前
Unity3D中管理Shader效果详解
开发语言·游戏·unity·unity3d·游戏开发
Ljw...7 天前
C++游戏开发
c++·c·游戏开发
AgilityBaby14 天前
UE5蓝图中整理节点的方法
ue5·游戏引擎·unreal engine·1024程序员节
北冥没有鱼啊16 天前
ue5 扇形射线检测和鼠标拖拽物体
游戏·ue5·ue4·游戏开发·虚幻
孙_华鹏18 天前
高德地图游戏解决方案——结合threejs仿某猫捉猫猫得红包游戏
前端·typescript·游戏开发
会做游戏的小蜗牛20 天前
从零到一:前端开发者学习 Cocos Creator 的全攻略
前端·游戏开发
黑不溜秋的20 天前
染引擎实践 - UnrealEngine引擎中RHI实现分析
unreal engine
Thomas_YXQ21 天前
Unity3D中Excel表格的数据处理模块详解
linux·windows·算法·excel·unity3d·游戏开发
程序员Winn21 天前
HR的骚操作,真的是卧龙凤雏!
面试·游戏开发·求职
侑虎科技21 天前
Fluid Flux2.0海浪原理拆解
性能优化·unreal engine