Mecanim动画系统(三)
一、初识Blend Trees(混合树)
● 混合树 用于两个或多个类似动画的融合。如从walk到run的速度的变化,或在奔跑的时候向左、向右的倾斜角度。
● 2D Simple Directional(简单的定向): 表示在二维每个空间方向只能有一个动作
适用于当你的动作片段代表不同方向时,如“向前行走”、“向后行走”、“向左行走”和“向右行走”或是“向上瞄准”、“向下瞄准”、“向左瞄准”和“向右瞄准”。选一个基础动作放在位置 (0, 0) 处,如 “idle” 和“aim straight”等。在简单方向 (Simple Directional) 类型中,相同方向上不应存在多个运动,如“向前行走”和“向前奔跑”。
● 2D Freeform Directional(自由的定向): 表示在二维每个空间方向可以有多个动作
这种类型同样用于当你的动作片段代表不同方向时使用,但是你可以在相同方向上具有多个动作,例如“向前行走”和“向前奔跑”。在任意方向 (Freeform Directional) 类型中,在该类型中应设置一个动作在位置 (0, 0)处,如“idle”。
● 2D Freeform Cartesian(自由的坐标):
适用于你的动作中不需要代表不同方向时。如你要做的游戏中包括“向前行走不转弯”、“向前奔跑不转弯”、同时可以“向前行走并右转”、“向前奔跑并右转”等运动时,使用这种类型。
● Direct:能够精准的控制每个动画所占的权重(每个动画占用一个不同的float值)。如下图:
● Automate Threshold: 自动化阙值(阙值:临界值)
1、1D 混合树
● Parameter: 参数类型
● Thresholds:阙值。当“Blend Tree”的数值达到某个动画的阙值时,则完全播放该动画
● 在“1D 混合树”中用代码实现walk到run的过度
//按下W、S键实现"WalkRun"参数由-1到1的动态变化
float y = Input.GetAxis("Vertical");
_animator.SetFloat("WalkRun", y);
2、2D 混合树
● 2D Freeform Cartesian
//按下W、S、A、D键实现行走动画的过度
float x = Input.GetAxis("Horizontal");
float y = Input.GetAxis("Vertical");
_animator.SetFloat("h", x);
_animator.SetFloat("v", y);
二、Mecanim动画系统的简单应用
1、遮罩(用于两种动画的不同部位同时播放,如边奔跑边射击等)
● Weight:权重。基础层的权重为默认
● Mask : 遮罩
● Blending:该层动画与其他层动画的混合方式,包括Override(复写方式,即取不同层动画的中间值)和additive(直接叠加)。
● Sync:同步。同步是本层动画直接同步其他层动画状态之间的逻辑状态,一般需要选取同步源。同步之后需要给本层的动画状态添加动画剪辑。
● IK Pass:即本层动画是否支持IK动画。
1)在Layers中新建一个图层“Layer_attack”,调整权重(Weight)、添加动画。
2)右键新建一个Avatar Mask遮罩并调节Humanoid属性,然后在Mask图层中添加遮罩。新建Avatar Mask如下图:
3)可以在Blending属性中将Override改为additive(直接叠加),得到不同的效果
2、动画重定向
1、直接将建好的Animator Controller赋给角色模型
2、在Project视图中右键新建一个Animator Override Controller然后将Animator Controller赋给他。方法二的好处是可以将“Animator Controller”重新命名便于区分。
注意:需要注意Avatar下面有没有Configure Avatar选项,如果没有则需要重新设置Animation Type和Avatar Definition。否则无法进行动画重定向。如下图
3、IK
IK(Inverse Kinematics)即反向动力学,即可以使用场景中的各种物体来控制和影响角色身体部位的运动,一般来说骨骼动画都是传统的从父节点到子节点的带动方式(即正向动力学),而IK则倒过来,由骨骼子节点带动骨骼父节点。(插件:FinalIK)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 在Animator Controller添加一个idle
/// 在Hierarchy窗口创建一个游戏物体给角色用
/// 开启IK Pass,绑定脚本即可
/// </summary>
public class IKController : MonoBehaviour
{
//声明
Animator _animator;
public Transform lookAtObj = null;
public Transform rightHandObj = null;
void Start()
{
_animator = GetComponent<Animator>();
}
void OnAnimatorIK()
{
if (_animator)
{
if (lookAtObj != null)
{
_animator.SetLookAtWeight(1);//设置权重
_animator.SetLookAtPosition(lookAtObj.position);
}
else _animator.SetLookAtWeight(0);
if (rightHandObj != null)
{
//“AvatarIKGoal.RightHand”右手的权重为1
_animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1);
_animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 1);
//右手的位置和旋转角度
_animator.SetIKPosition(AvatarIKGoal.RightHand, rightHandObj.position);
_animator.SetIKRotation(AvatarIKGoal.RightHand, rightHandObj.rotation);
}
else
{
_animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 0);
_animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 0);
}
}
}
}
4、用代码触发开门动画
1)选中门利用Unity创建一个简单的开门动画;
2)在Project视图创建一个Animation动画(静态的)作为默认动画;
3)连接如下图:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerController : MonoBehaviour { private AudioSource _audioSource; private Animator _animation; void FixedUpdate() { Move(); } void Move() { //角色移动 //运行时需要在"Rigidbody"组件上设置constraints(轴约束),否则角色胶囊无法保持平衡 transform.Translate(0, 0, Input.GetAxis("Vertical") * Time.deltaTime * 5); transform.Rotate(0, Input.GetAxis("Horizontal") * Time.deltaTime * 50, 0); } void OnTriggerEnter(Collider other) { //使用OnTrigger方法必须在游戏物体或者角色上开启“Is Trigger” //如果触发标签为"door"的游戏对象,则播放声音及开门动画 //如果获取组件不添加“other”,则默认获取的是当前绑定脚本的游戏对象 if (other.tag == "door") { _audioSource = other.GetComponent<AudioSource>(); _audioSource.Play(); _animation = other.GetComponent<Animator>(); _animation.SetTrigger("door1"); } } void OnTriggerExit(Collider other) { if (other.tag == "door") { _audioSource = other.GetComponent<AudioSource>(); _audioSource.Play(); _animation.SetTrigger("door0"); } } }