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

使用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

时间: 04-12

Mecanim Control试用——模拟前进加速过程的相关文章

编写三各类Ticket、SaleWindow、TicketSaleCenter分别代表票信息、售票窗口、售票中心。 售票中心分配一定数量的票,由若干个售票窗口进行出售,利用你所学的线程知识来模拟此售票过程。

package com.swift; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class TicketSaleCenter { public static void main(String[] args) { /* * 第6题: 编写三各类Ticket.SaleWindow.TicketSaleCenter分别代表票信息.售票

淘宝试用 模拟点击程序

一个模拟点击事件的程序.试用python语言.循环点击淘宝试用的宝贝.由于平时中过几次淘宝试用,认为有这种机会白不用,所以自己写了个小程序,免去人为琐碎的点击申请宝贝. 代码开源在github https://github.com/Rockyzsu/TaobaoTrial

使用httpClient模拟登陆开心网过程中登陆成功但是跳转不成功

package com.haojiahong.test; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ResponseHandler; import org.apache.http.client.entity.UrlEncodedF

ConcurrentLinkedQueue 模拟火车售票过程

火车票类 public class Ticket { private String NO; // 车票编号 private double price; // 票价 public Ticket(String nO, double price) { super(); NO = nO; this.price = price; } public String getNO() { return NO; } public void setNO(String nO) { NO = nO; } public d

Mysql模拟故障恢复案例过程

一.数据库全备,全备脚本如下: [[email protected] script]# cat bak_all.sh #!/bin/bash#Date: 2019-12-08#Author: chan#Mail: chan#Function:This scripts function is More complex backup scripts which need to find binlog log files and location points #Version: 1.1 USER=r

python模拟websocket握手过程中计算sec-websocket-accept

背景 以前,很多网站使用轮询实现推送技术.轮询是在特定的的时间间隔(比如1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给浏览器.轮询的缺点很明显,浏览器需要不断的向服务器发出请求,然而HTTP请求的header是非常长 的,而实际传输的数据可能很小,这就造成了带宽和服务器资源的浪费. Comet使用了AJAX改进了轮询,可以实现双向通信.但是Comet依然需要发出请求,而且在Comet中,普遍采用了长链接,这也会大量消耗服务器带宽和资源. 于是,WebSocke

【好记性不如烂笔头】约瑟夫环问题之形象解法(其实就是实实在在的模拟一下游戏过程)

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace 约瑟夫环游戏 8 { 9 class Program 10 { 11 /* 12 * 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围. 13 * 从编号为k的

Oracle11gr2_ADG管理之在备库上模拟failover的过程实战

技术建议和方案. 要求failover后不重建备库,并能够把failover的数据库重新切换回备库 主库为newtest,备库为snewtest 备库上已经开启了闪回 得到一个参考的SCN SQL> select current_scn from v$database; CURRENT_SCN ----------- 4491930 查看闪回数据库特性是打开的. SQL> select flashback_on from v$database; FLASHBACK_ON -----------

案例三:小明左右手分别拿两张纸牌:黑桃10和红心8,现在交换手中的牌。编写一个程序模拟这一个过程:两个整数分别保存在两个变量中,将这两个变量的值互换,并输出互换后的结果。

package project_03; /** * 2018-9-7 20:19:59 * @author Sauron XiaMen * */ public class ChangeCard { //将两个变量的值互换 public static void main(String[] args) { System.out.println("输出互换前手中的纸牌:"); int left=10; int right=8; int i=0; System.out.println(&quo