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");
        }
    }
}

 

posted @ 2017-03-26 09:48  LiuChangwei  阅读(1944)  评论(0编辑  收藏  举报