Mecanim Control试用――模拟前进加速过程

    使用Mecanim动画系统有时会遇到大量转换连线导致状态图特别复杂杂乱。这时很多人希望能像旧的动画系统Animation那样用Play()函数来控制动画。Mecanim Control正式解决这问题的方案。

    获取MecanimControl插件。官网购买地址https://www.assetstore.unity3d.com/en/#!/content/15156

    新建Unity工程,导入MecanimControl。另下载并导入MecanimExampleScenes1.0作为动画测试资源。

    任务:模拟一个人从站立待机开始->向前走动->->慢停->待机结束。

    

1、创建场景配置属性

    在Raw Mocap Data资源目录下找到DefaultAvatarwKioL1UqHRjwcMfmAAA3r-jmur4262.jpg,拖到场景中。准备动画资源,默认的动画资源是一个完整合集,我们要挑出合适的剪辑成最终需要的。挑选Idle_Neutral_1,添加一个剪辑起始是75,结束150帧处,命名为IdlewKioL1UqI9-zLZVpAABu983Rt5w695.jpg。然后按下表准备好动画剪辑。

描述
原始资源名
动画剪辑名
起始帧
结束帧 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插件。


补充:transitionDuration一般设为-1,0值不会有过度非常生硬


欢迎Unity爱好者加入QQ群255316030

你可能感兴趣的:(unity,animation,animator)