你的位置:首页 > 操作系统

[操作系统]Unity利用AnimationCurve做物体的各种运动


​之前一直都是自己学习Unity各种做Demo,最近开始正式使用Unity来做一个款2d的游戏。

其中在做一个类似小球弹跳运动的时候遇到了点问题,查找了很多资料,无意间发现AnimationCurve,顿时那种心情啊!

然后苦心钻研了一翻 抛砖引玉 的写了个Move2D的类主要是个大家一个思路。

不多说上正菜:

直线平移运动效果:

曲线上升运动效果:

曲线上升然后下降的弧线运动效果:

小球弹跳运动效果:

 

下面是C#代码,由于之前一直用Cocos2d-x所以有点cocos的风格:

using UnityEngine;using System.Collections;public class Move2D : MonoBehaviour {  private float moveTime = 0;  private Vector3 speed;  private float timeDelta = 0;  private AnimationCurve anmc = null;  private bool isMoveRuning = false;  public bool IsMoveRuning  {    get{return isMoveRuning;}  }  private static Move2D createMove(GameObject runObj)  {    Move2D move2d = runObj.GetComponent<Move2D>();    if(move2d == null){      move2d = runObj.AddComponent<Move2D>();    } else {      //可以在这地方做标志达到动作序列,动作融合等等    }        return move2d;  }  /// <summary>  /// 创建一个轨迹是直线的运动  /// </summary>  /// <returns>返回 Move2D 运动实例</returns>  /// <param name="runObj">执行运动的物体</param>  /// <param name="endPostion">运动的终点</param>  /// <param name="moveTime">运动的时间</param>  public static Move2D createMove_Line(GameObject runObj,Vector3 endPostion,float moveTime)  {    Move2D move2d = createMove(runObj);    move2d.initMove_Line(endPostion,moveTime);        return move2d;  }  private void initMove_Line (Vector3 endPostion,float moveTime)  {    //直线运动不需要曲线进行y方向位移    anmc = null;    isMoveRuning = true;    speed = endPostion / moveTime;    timeDelta = 0;    this.moveTime = moveTime;  }  /// <summary>  /// 创建一个轨迹是曲线上升的运动  /// </summary>  /// <returns>返回 Move2D 运动实例</returns>  /// <param name="runObj">执行运动的物体</param>  /// <param name="endPostion">运动的终点</param>  /// <param name="moveTime">运动的时间</param>  /// <param name="maxHeight">曲线的最大高度,在这个运动中指的是物体最终停留的高度</param>  /// <param name="curveCoefficient">曲线弧度系数.默认有一个系数计算方法,但是我只测试了高度为1-10的情况.如果运动曲线不是你期望的那么传入你需要的参数</param>  public static Move2D createMove_CurveUp(GameObject runObj,Vector3 endPostion,float moveTime,float maxHeight,float curveCoefficient = -999999f)  {    Move2D move2d = createMove(runObj);    //测试范围 1-10 都没有问题,如果有问题的话自己传入curveCoefficient    if(curveCoefficient == -999999f){      curveCoefficient = maxHeight * 0.5f;    }    move2d.initMove_CurveUp(endPostion,moveTime,maxHeight,curveCoefficient);    return move2d;  }  private void initMove_CurveUp (Vector3 endPostion,float moveTime,float maxHeight,float curveCoefficient)  {    //以下注释内容引用自 风宇冲的博客    //http://blog.sina.com.cn/s/blog_471132920101f8nv.html    //脚本创建AnimationCurve    //AnimationCurve可以理解为2部分 (1)键序列 (2)左右循环模式(又作左右包裹模式)    //一:键序列    //创建键序列:Keyframe[] ks = new Keyframe[3];    //曲线中加入键序列:AnimationCurve curve = new AnimationCurve(ks);    //获取曲线中的键序列:curve[index]  或者 curve.keys[index]    //添加单键:curve.Addkey(time,value)    //删除单键:curve.RemoveKey(index)    //二:左右循环    //anim.preWrapMode = WrapMode.Loop;    //anim.postWrapMode = WrapMode.Once;    //三:键    //Keyframe kf = new Keyframe(time,value);    //kf.inTangent = 45;    //kf.outTangent = 45;    Keyframe[] kfs = new Keyframe[2];    kfs[0] = new Keyframe(0,0);    kfs[0].outTangent = curveCoefficient;    kfs[1] = new Keyframe(moveTime,maxHeight);    anmc = new AnimationCurve(kfs);    isMoveRuning = true;    speed = endPostion / moveTime;    timeDelta = 0;    this.moveTime = moveTime;  }  /// <summary>  /// 创建一个轨迹是曲线上升到最大高度后下降的运动,当终点等于起点的时候就是原地跳跃  /// </summary>  /// <returns>返回 Move2D 运动实例</returns>  /// <param name="runObj">执行运动的物体</param>  /// <param name="endPostion">运动的终点</param>  /// <param name="moveTime">运动的时间</param>  /// <param name="maxHeight">曲线的最大高度,在这个运动中指的是物体运动轨迹的最大高度</param>  /// <param name="curveCoefficient">曲线弧度系数.默认有一个系数计算方法,但是我只测试了高度为1-10的情况.如果运动曲线不是你期望的那么传入你需要的参数</param>  public static Move2D createMove_CurveUpDown(GameObject runObj,Vector3 endPostion,float moveTime,float maxHeight,float curveCoefficient = -999999f)  {    Move2D move2d = createMove(runObj);    //测试范围 1-10 都没有问题,如果有问题的话自己传入curveCoefficient    if(curveCoefficient == -999999f){      if(maxHeight >= 3)curveCoefficient = ((maxHeight-3f) * 0.5f) + 2.5f;      else {        curveCoefficient = maxHeight * 0.5f;      }    }    move2d.initMove_CurveUpDown(endPostion,moveTime,maxHeight,curveCoefficient);        return move2d;  }    private void initMove_CurveUpDown (Vector3 endPostion,float moveTime,float maxHeight,float curveCoefficient)  {    Keyframe[] kfs = new Keyframe[3];        kfs[0] = new Keyframe(0,0);    kfs[0].outTangent = curveCoefficient;    kfs[1] = new Keyframe(moveTime/2,maxHeight);    kfs[1].inTangent = 0f;    kfs[1].outTangent = 0f;    kfs[2] = new Keyframe(moveTime,0);    kfs[2].inTangent = -curveCoefficient;        anmc = new AnimationCurve(kfs);    isMoveRuning = true;    speed = endPostion / moveTime;    timeDelta = 0;    this.moveTime = moveTime;  }  /// <summary>  /// 创建一个轨迹是落地弹跳小球的运动  /// </summary>  /// <returns>返回 Move2D 运动实例</returns>  /// <param name="runObj">执行运动的物体</param>  /// <param name="endPostion">运动的终点</param>  /// <param name="moveTime">运动的时间</param>  /// <param name="maxHeight">曲线的最大高度,在这个运动中指的是物体运动轨迹的第一个波峰高度,第二个波峰高度是最大高度的1/3,第三个波峰最大高度是第一个的1/5</param>  /// /// <param name="curveCoefficient">曲线弧度系数.默认有一个系数计算方法,但是我只测试了高度为1-10的情况.如果运动曲线不是你期望的那么传入你需要的参数</param>  public static Move2D createMove_Bounce3(GameObject runObj,Vector3 endPostion,float moveTime,float maxHeight,float curveCoefficient = -999999f)  {    Move2D move2d = createMove(runObj);    //测试范围 1-10 都没有问题,如果有问题的话自己传入curveCoefficient    if(curveCoefficient == -999999f){      curveCoefficient = maxHeight;    }    move2d.initMove_Bounce3(endPostion,moveTime,maxHeight,curveCoefficient);        return move2d;  }    private void initMove_Bounce3 (Vector3 endPostion,float moveTime,float maxHeight,float curveCoefficient)  {    Keyframe[] kfs = new Keyframe[7];        kfs[0] = new Keyframe(0,0);    kfs[0].outTangent = curveCoefficient;    kfs[1] = new Keyframe(moveTime*0.35f,maxHeight);    kfs[1].inTangent = 0;    kfs[1].outTangent = 0;        kfs[2] = new Keyframe(moveTime*0.7f,0);    kfs[2].inTangent = -curveCoefficient;    kfs[2].outTangent = curveCoefficient/2f;    kfs[3] = new Keyframe(moveTime*0.8f,maxHeight/3);    kfs[3].inTangent = 0;    kfs[4].outTangent = 0;    kfs[4] = new Keyframe(moveTime*0.9f,0);    kfs[4].inTangent = -curveCoefficient/2f;    kfs[4].outTangent = curveCoefficient/2f;    kfs[5] = new Keyframe(moveTime*0.95f,maxHeight/5);    kfs[5].inTangent = 0;    kfs[5].outTangent = 0;        kfs[6] = new Keyframe(moveTime,0);    kfs[6].inTangent = -curveCoefficient/2f;        anmc = new AnimationCurve(kfs);    isMoveRuning = true;    speed = endPostion / moveTime;    timeDelta = 0;    this.moveTime = moveTime;  }  void Update () {    if(timeDelta <= moveTime){      Vector3 ep = speed * timeDelta;            if(anmc != null){        ep.y += anmc.Evaluate(timeDelta);      }            transform.localPosition = ep;      timeDelta += (Time.deltaTime);    } else {      StopMove2D();    }  }  public void StopMove2D()  {    Destroy(this);    isMoveRuning = false;  }}

使用的时候create你需要的运动就好:

void Start () {//    Move2D.createMove_Line(gameObject,new Vector3(10,5,0),5f);//    Move2D.createMove_CurveUp(gameObject,new Vector3(10,2,0),5f,2f);    Move2D.createMove_CurveUpDown(gameObject,new Vector3(10,3,0),5f,3f);//    Move2D.createMove_Bounce3(gameObject,new Vector3(10,1,0),5f,4f);  }

没有什么难点主要是对AnimationCurve的运用

我只是 抛砖引玉 具体是要你项目需求,比如运动结束的回调等等我还没有添加。

这里不知道怎么上传附件,如果需要看Demo的话去这里​的附件下载把,如果有后面有更新我也会放在这里的。

最后感谢风宇冲的博客提供的帮助,如果有具体不知道怎么操作的小伙伴可以去看这个博客,里面详细的介绍了怎么用AnimationCurve。

欢迎转载收藏,转载著名出处!