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

  • 暂未解决的问题,角色下落会滑翔,但是如果在跳跃时没有按住按钮就不会滑翔。
相关推荐
北桥苏2 天前
如何在 Unity3D 中实现圆角效果?
unity3d·游戏开发
UWA2 天前
Gears实测室:第一期·音游跨设备性能表现与工具价值实践
信息可视化·性能优化·游戏开发·uwa
红红大虾3 天前
Defold核心概念之Message Passing
游戏开发
红红大虾4 天前
Defold核心概念之Building Blocks
游戏开发
Mr_1479 天前
【独游开发必备】游戏开发资源宝藏网站(美术篇)
游戏开发
Aoife婳10 天前
【Bug】UE5中纹理和地形一直闪烁
游戏开发
龚子亦11 天前
【Unity开发】丧尸围城项目实现总结
unity·游戏引擎·游戏开发
小哈里14 天前
【Game-Infra】游戏开发的流程,游戏发布的打包与构建(硬件选型,SDK与操作系统,包体管理,弹性构建,构建调优)
游戏·游戏开发·后端开发·基础设施·打包构建·游戏发布·弹性构建
小强Fnsy14 天前
一款将GIF、序列帧的指定选区转换成新的序列帧,并导出为Plist、PNG、GIF的工具
前端·游戏开发
Thomas游戏开发17 天前
Unity Android性能优化设置指南
前端框架·unity3d·游戏开发