从Unity 4发布了Mecanim动画系统后,有不少的朋友仍然没有放弃3.5.x的版本,其中的一个原因4.x版本的默认是无法判断模型导入的动作,需要手动更改为Legacy才能正确的进行动作的播放。而另一个原因是,不明白Mecanim的动画管理有何优势,对于这点,我们将以一个简单的案例来说明Mecanim的妙用之处。
场景里面是一个导入的角色模型,采用了Humanoid 的动作类型,如果角色动作不打算套用在其他的模型上面,则采用Generic的类型即可,而选择Legacy的话就表示采用3.5.x版本的动作模式。
打开角色的Animation Controller,在Base Layer的动画层里已经设置了角色前后与左右移动,现在的问题是,如果我们需要在角色移动的同时叠加另一个动作,例如角色一边跑,一边做武器的更换,或是做装填子弹的动作,而武器的更换与子弹装填是另外的动作,那么应该如何设置呢?
按下+号新增一个动画层,将这个层命名为Layer2,Weight是动画层的权重,Mask则是接下来需要自行建立的部分。
在Project目录下新增一个Avatar Mask,名称自行定义即可,然后在Mask里面指定这个新增的Avatar Mask。
双击打开Avatar Mask,里面是一个人形的图示,绿色的部分表示该关节位置允许叠加到Base Layer,而我们现在需要的是手臂的动作来执行武器的更换与子弹装填,所以必须关闭不需要的关节位置。
如图所示,点击不需要的关节位置使其成为红色状态即可,这样就能让此动画层仅有手臂的动作会叠加到Base Layer。
接着在Layer2里面新增一个New State与两个Blend Tree, 我们需要将武器的更换与子弹装填的动作添加到这两个Blend Tree。
如图所示,将两个Blend Tree更换名称并指定动作后,在Parameters里面新增两个Bool,分别命名为Reloading与SwitchWeapon,再使用Make Transition将New State与两个Blend Tree进行连接。
从New State到Reloading与SwitchWeapon的连接采用了True,表示脚本里面所设置的按键按下后立即将false切换到true的执行状态。
从Reloading与SwitchWeapon回到New State的连接采用了默认的Exit Time,分别设置为0.4与0.8的数值,这里的作用是让Layer2的动作回到New State时能有一个融合的效果。
Animation Controller与Mask设置完成后,将以下的脚本添加到角色上面即可进行动作的测试,在角色移动的同时按下左键可执行一边跑步一边填充子弹,按下右键则是执行更换武器的动作。
角色代码使用的如下:- using UnityEngine;
- using System.Collections;
- // 自动添加角色需要的组件
- [RequireComponent(typeof (Animator))]
- [RequireComponent(typeof (CapsuleCollider))]
- [RequireComponent(typeof (Rigidbody))]
- public class PlayerControlScript : MonoBehaviour
- {
- [System.NonSerialized]
- public float meshMoveSpeed = 4.0f;
-
- [System.NonSerialized]
- public float animSpeed = 1.5f;
-
- private Animator anim;
- private AnimatorStateInfo currentBaseState;
- private AnimatorStateInfo layer2CurrentState;
- static int reloadState = Animator.StringToHash("Layer2.Reload");
- static int switchWeaponState = Animator.StringToHash("Layer2.WeaponSwap");
-
- void Start ()
- {
- anim = GetComponent<Animator>();
- if(anim.layerCount ==2)
- anim.SetLayerWeight(1, 1);
- }
-
- void OnAnimatorMove()
- {
- if(anim)
- {
- Vector3 newPosition = transform.position;
- newPosition.z += anim.GetFloat("Speed")* meshMoveSpeed * Time.deltaTime;
- newPosition.x += anim.GetFloat("Direction") * meshMoveSpeed * Time.deltaTime;
- transform.position = newPosition;
- }
- }
-
-
- void FixedUpdate ()
- {
- float h = Input.GetAxis("Horizontal");
- float v = Input.GetAxis("Vertical");
- anim.SetFloat("Speed", v);
- anim.SetFloat("Direction", h);
- anim.speed = animSpeed;
- //anim.SetLookAtWeight(lookWeight);
- currentBaseState = anim.GetCurrentAnimatorStateInfo(0);
-
- //Controls the movement speed
- if(v <= 0.0f)
- {
- meshMoveSpeed = 4;
- }
- else
- {
- meshMoveSpeed = 6;
- }
-
- if(anim.layerCount ==2)
- {
- layer2CurrentState = anim.GetCurrentAnimatorStateInfo(1);
- }
-
- if(Input.GetButtonDown("Fire1"))
- {
- anim.SetBool("Reloading", true);
- }
- else
- {
- anim.SetBool("Reloading", false);
- }
-
- if (layer2CurrentState.nameHash != reloadState || currentBaseState.nameHash != switchWeaponState)
- {
- if(Input.GetButtonUp("Fire2"))
- {
- anim.SetBool("SwitchWeapon", true);
- }
- }
- if (layer2CurrentState.nameHash == switchWeaponState)
- {
- anim.SetBool("SwitchWeapon", false);
- }
- }
- }
复制代码 |