# 骨骼动画入门指引
在游戏开发中,通常使用骨骼动画来实现人物、怪物等的表现。
本章节我们将使用一个简单的例子来介绍如何在小游戏3D中使用骨骼动画
# 模型资源导入
通常带动画的模型资源来自于第三方建模工具,如Maya、3DSMax,目前小游戏3D仅支持fbx格式的模型及动画资源导入。
由于fbx是一种复合资源格式,其中可能包含模型网格、材质、贴图、动画、骨架等资源,在小游戏3D中,一个fbx中包含的所有资源都可以被单独使用,这样可以实现一些工程优化需求,例如一个动画片段被多个角色复用等。
将fbx文件放入assets目录,即可在Project目录下看到。点击fbx右边的箭头,即可展开其中包含的所有资源。
随后在Hierarchy面板中右键->添加Prefab,选择Running.fbx,即可添加进场景中。
点击播放,即可看到播放人物正常运动
如果你的动画资源来自于第三方游戏引擎,请参考转换方案
章节。
# 使用挂点
游戏中一个很常见的需求就是人物手持武器或者挂件,通常的做法是将武器的模型作为人物手部骨骼节点的子节点。 在小游戏框架中,基于性能考虑,人物的骨架节点并不是作为场上节点存在的。所以小游戏框架提供了挂点的机制。
这里我们以一个简单的模型代替武器来说明挂点的用法。在Running
下创建一个Hand节点,创建一个Capsure
模型作为其子节点,调整Capsure
节点的属性到合适大小。
在Running
节点的Skeleton
组件中点击Animation Remapping Configuration
的Edit
按钮,进入到骨架节点配置模式。找到左手的骨架节点,将Hierarchy
面板中Hand
节点拖入Model Binding Transform
字段中,该操作表示左手的骨架节点的Transform信息会被实时同步到场上的Hand
节点,即Hand
成为模型的挂点。
- 注意: 挂点节点必须是Skeleton所在节点的
直接子节点
点击Apply
可以应用刚刚的骨架节点配置。
预览场景,可以看到模型会跟随手进行运动,Hand节点的Transform组件属性也会每帧更新
# 提取资源
本章的例子中,直接运行Running会看到动画只播了一次。如果需要循环,则需要修改AnimationClip,此时我们就需要提取资源。
Project中右键Running.fbx,选择提取。则可看到同路径下创建了Running的目录,其中包含了fbx里所含的所有资源,包含一个Prefab,以及其所依赖的Mesh、Material、Texture、AnimationClip、Avatar等
将Running目录中解包后的prefab添加到场上,随后对AnimationClip修改设置为Loop。运行场景即可看到生效。
# 使用动画状态机
在游戏中人物或怪物的动作常被定义为一个状态机的形式,人物的走、跑、跳等都被作为其中的状态。小游戏框架提供了对动画状态机的支持。
在小游戏框架中,使用AnimatorController资源表示对动画状态机的配置,使用Animator组件对动画进行控制和管理。
# 创建动画控制器(AnimatorController)
在Project目录下右键->新建->Animation->animatorcontroller,可以创建AnimatorController资源。然后新增标签->Animation->Animator打开动画Animator面板,即可进入动画状态机的编辑界面。
# 添加状态(State)
在动画状态机视图的网格位置右键->Create State->Empty,即可创建一个State。选中这个State,在Inspector面板中可以编辑详情。这里我们修改name为Running,并且选择Motion为Running的动画片段。
同时我们以相同的方法创建一个Idle的State,表示站立时的状态;创建一个Jump的State,表示跳跃的状态。 在Idle状态上右键->Set As Layer Default State,即可将Idle变成默认状态。
点上方绿色的保存按钮,保存目前为止的编辑状态。
# 使用Animator组件
在模型的Inspector面板中,添加组件->Animation->Animator,为物体添加一个Animator组件,同时可以把Animation组件禁用或删除。
将controller字段设置为刚刚创建的AnimatorController资源,播放场景,即可看到动画默认在播放Idle动作
如果想要了解更多Animator组件相关的内容,请参考Animator组件参考章节
# 在不同状态之间切换
我们在模型上添加一个自定义Script组件,命名为TestAnimator,并复制以下代码保存
import engine from "engine";
@engine.decorators.serialize("TestAnimator")
export default class TestAnimator extends engine.Script {
public animComp: engine.Animator;
public onStart() {
this.animComp = this.entity.getComponent(engine.Animator);
setTimeout(() => {
this.animComp.crossFade("Base Layer.Running",0.5);
}, 3000);
setTimeout(() => {
this.animComp.crossFade("Base Layer.Jump",0.5);
}, 5000);
}
}
播放场景,即可看到动画由站立平滑过度至跑步动作,又平滑过度至跳跃。
;
# 设置状态机的转移关系
实际应用中,状态之间的转移关系及条件通常会很复杂,使用代码控制难以维护。小游戏框架提供了一套状态转移编辑与控制机制。
打开Animator面板,在Idle状态上右键->Make Transition->点击Running,即可建立Idle
和Running
之间的状态转移。用同样的方法建立Running
与RunningJump
之间的双向转移。
选择左侧的Paramerters,添加一个Float
类型的参数speed
和一个Trigger
类型的参数jump
。
接下来我们要为状态转移配置条件(condition)。点击Idle和Running之间的箭头,在Inspector面板下即可看到该转移的详情。在Conditions下添加一个speed Greater 0
的条件
同理我们在Running
指向RunningJump
的转移中添加jump
的条件
最后我们修改TestAnimator脚本,运行时使用代码触发Parameter变动
import engine from "engine";
@engine.decorators.serialize("TestAnimator")
export default class TestAnimator extends engine.Script {
public animComp: engine.Animator;
public onStart() {
this.animComp = this.entity.getComponent(engine.Animator);
setTimeout(() => {
this.animComp.setFloat("speed",1.0);
}, 3000);
setTimeout(() => {
this.animComp.setTrigger("jump");
}, 5000);
}
}
预览场景,即可看到效果