使用Mecanim动画系统有时会遇到大量转换连线导致状态图特别复杂杂乱。这时很多人希望能像旧的动画系统Animation那样用Play()函数来控制动画。Mecanim Control正式解决这问题的方案。
获取MecanimControl插件。官网购买地址https://www.assetstore.unity3d.com/en/#!/content/15156
新建Unity工程,导入MecanimControl。另下载并导入MecanimExampleScenes1.0作为动画测试资源。
任务:模拟一个人从站立待机开始->向前走动->跑->慢停->待机结束。
1、创建场景配置属性
在Raw Mocap Data资源目录下找到DefaultAvatar
,拖到场景中。准备动画资源,默认的动画资源是一个完整合集,我们要挑出合适的剪辑成最终需要的。挑选Idle_Neutral_1,添加一个剪辑起始是75,结束150帧处,命名为Idle
。然后按下表准备好动画剪辑。
| 描述 | 原始资源名 | 动画剪辑名 | 起始帧 | 结束帧 | Wrap |
| 待机 | Idle_Neutral_1 | Idle | 75 | 150 | Loop |
| 走动 | WalkFWD | Walk | 0 | 30 | Loop |
| 跑 | Run_Impulse | Run | 163 | 181 | Loop |
| 跑停 | Run_FastStop_Idle | RunStop | 83 | 161 | Once/Clamp |
| 走停 | WalkJump_ToLeft_R_1 | WalkStop | 440 | 474 | Once/Clamp |
添加MecanimControl脚本,配置好的动画剪辑加入Animations参数。Speed都设为1,WrapMode按表中配置。
到此基本准备好了,因动画走、跑等这些不是在原地走动,播放动画时会一直往前走。所以我们要采取措施修正走路前进动画。这里创建一个GameObject命名为Player,将DefaultAvatar拖入Player,Reset Transform的属性。给Player添加Rigidbody组件,勾掉Use Gravity。后面会用代码修正DefaultAvatar的LocalPostion的z值,这样便不会再有前进移动。
2、代码
新建cs脚本,命名为MecanimControlTest。代码思路通过W键来控制前进还是停止前进,这部分代码在FixedUpdate里。根据当前的运动状态来切换动画,这部分代码在Update里。真实开发中摆臂、跨步动作要拆分出先左还是先右才能连贯。用速度来控制动画状态的切换。
测试中发现一个问题,Walk、Run动画在连续循环后方向会发生偏移。为了方便测试在FixedUpdate中对LocaRotation做复位处理。以前在项目中也常常遇到使用Animtor时Position和Rotation一个周期后会产生偏移,重复循环后非常明显。网络上的方案是调整动画剪辑的Based Upon来解决,实际发现只有少部分能解决。哪位大大知道有效的解决方案欢迎交流。
下面附上MecanimControlTest.cs的代码。
using UnityEngine;
using System.Collections;
public class MecanimControlTest : MonoBehaviour {
public Rigidbody body; // 赋值Player
public MecanimControl mecanimControl; // 赋值
public float forwardForce = 3f; // 驱动力
public float brakeForce = 5f; // 制动力
public float runStartPoint = 3f; // 开始跑动的速度
public float maxForwardSpeed = 7f; // 最大速度
private bool mKeyDown;
/// <summary>
/// 行驶
/// </summary>
private bool mDrive;
/// <summary>
/// 制动,运动行驶中松掉W键刹车。
/// </summary>
private bool mBrake {
get {return mDrive && !mKeyDown;}
}
private AnimState mCurrentAnimState = AnimState.Idle;
public enum AnimState {
Idle,
Walk,
Run,
RunStop,
WalkStop,
}
// Use this for initialization
void Start() {
mecanimControl.Play ("Idle");
}
// Update is called once per frame
void Update () {
if ((mCurrentAnimState == AnimState.Idle || mCurrentAnimState == AnimState.WalkStop) && mKeyDown) { // idle/walkStop->walk
mecanimControl.CrossFade("Walk", 0.2f);
mCurrentAnimState = AnimState.Walk;
}
if ((mCurrentAnimState == AnimState.Walk || mCurrentAnimState == AnimState.RunStop) && body.velocity.magnitude >= runStartPoint
&& mKeyDown) { // walk/runStop->run
mecanimControl.CrossFade("Run", 0.2f);
mCurrentAnimState = AnimState.Run;
}
if (mBrake) {
if (mCurrentAnimState == AnimState.Walk) { // walk->walkStop
mecanimControl.CrossFade ("WalkStop", 0.2f);
mCurrentAnimState = AnimState.WalkStop;
}
if (mCurrentAnimState == AnimState.Run) { // run->runStop
mecanimControl.CrossFade ("RunStop", 0.2f);
mCurrentAnimState = AnimState.RunStop;
}
}
if (mCurrentAnimState != AnimState.Idle && !mDrive) { // walkStop/runStop->idle
mecanimControl.CrossFade("Idle", 0.2f);
mCurrentAnimState = AnimState.Idle;
}
}
void FixedUpdate() {
Vector3 pos = mecanimControl.transform.localPosition;
pos.z = 0;
mecanimControl.transform.localPosition = pos;
mecanimControl.transform.localRotation = Quaternion.identity;
mKeyDown = Input.GetKey (KeyCode.W);
if (mKeyDown) {
mDrive = true;
if (body.velocity.magnitude > maxForwardSpeed) {
body.velocity = Vector3.forward * maxForwardSpeed;
} else {
body.AddForce(Vector3.forward * forwardForce, ForceMode.Force);
}
}
if (mBrake) {
if (body.velocity.z <= 0.0001f) {
body.velocity = Vector3.zero;
mDrive = false;
} else {
body.AddForce(Vector3.back * brakeForce, ForceMode.Force);
}
}
}
}工程超出上传限制移植资料里下载(资源上传后一直看不到下载链接,后面补上)。MecanimControl不是开源,项目中把它移除。下载工程测试前请先导入MecanimControl插件。
欢迎Unity爱好者加入QQ群255316030
本文出自 “Toto” 博客,请务必保留此出处http://visualparkzhao.blog.51cto.com/10059377/1631605
原文:http://visualparkzhao.blog.51cto.com/10059377/1631605