Unity利用AnimationCurve做物体的各种运动

时间:2023-01-02 21:54:11

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

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

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

不多说上正菜:

直线平移运动效果:

Unity利用AnimationCurve做物体的各种运动

曲线上升运动效果:

Unity利用AnimationCurve做物体的各种运动

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

Unity利用AnimationCurve做物体的各种运动

小球弹跳运动效果:

Unity利用AnimationCurve做物体的各种运动

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

using UnityEngine;
using System.Collections; public class Move2D : MonoBehaviour
{
public delegate void OverMoveEventHandler(GameObject gObj);
public event OverMoveEventHandler OverMove; public delegate void RunTimeEventHandler(GameObject gObj,RunTimeEventArgs bte);
public event RunTimeEventHandler RunTime;
public class RunTimeEventArgs : System.EventArgs
{
public readonly float runTime;
public readonly float totalTime; public RunTimeEventArgs (float rt,float tt)
{
runTime = rt;
totalTime = tt;
}
} private float moveTime = ;
private Vector3 speed;
private float timeDelta = ; private AnimationCurve anmc = null; private bool isMoveRuning = false;
public bool IsMoveRuning
{
get{return isMoveRuning;}
} private Vector2 moveEndPosition;
public Vector3 MoveEndPosition
{
get{return moveEndPosition;}
} 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; moveEndPosition = endPostion;
speed = endPostion / moveTime;
timeDelta = ;
this.moveTime = moveTime;
isMoveRuning = true;
} /// <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[]; kfs[] = new Keyframe(,);
kfs[].outTangent = curveCoefficient; kfs[] = new Keyframe(moveTime,maxHeight); anmc = new AnimationCurve(kfs); moveEndPosition = endPostion;
speed = endPostion / moveTime;
timeDelta = ;
this.moveTime = moveTime;
isMoveRuning = true;
} /// <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 >= )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[]; kfs[] = new Keyframe(,);
kfs[].outTangent = curveCoefficient; kfs[] = new Keyframe(moveTime/,maxHeight);
kfs[].inTangent = 0f;
kfs[].outTangent = 0f; kfs[] = new Keyframe(moveTime,);
kfs[].inTangent = -curveCoefficient; anmc = new AnimationCurve(kfs); moveEndPosition = endPostion;
speed = endPostion / moveTime;
timeDelta = ;
this.moveTime = moveTime;
isMoveRuning = true;
} /// <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[]; kfs[] = new Keyframe(,);
kfs[].outTangent = curveCoefficient; kfs[] = new Keyframe(moveTime*0.35f,maxHeight);
kfs[].inTangent = ;
kfs[].outTangent = ; kfs[] = new Keyframe(moveTime*0.7f,);
kfs[].inTangent = -curveCoefficient;
kfs[].outTangent = curveCoefficient; kfs[] = new Keyframe(moveTime*0.8f,maxHeight/);
kfs[].inTangent = ;
kfs[].outTangent = ; kfs[] = new Keyframe(moveTime*0.9f,);
kfs[].inTangent = -curveCoefficient;
kfs[].outTangent = curveCoefficient; kfs[] = new Keyframe(moveTime*0.95f,maxHeight/);
kfs[].inTangent = ;
kfs[].outTangent = ; kfs[] = new Keyframe(moveTime,);
kfs[].inTangent = -curveCoefficient; anmc = new AnimationCurve(kfs); moveEndPosition = endPostion;
speed = endPostion / moveTime;
timeDelta = ;
this.moveTime = moveTime;
isMoveRuning = true;
} void Update () {
if(timeDelta <= moveTime){
Vector3 ep = speed * timeDelta; if(anmc != null){
ep.y += anmc.Evaluate(timeDelta);
} transform.localPosition = ep; if(RunTime != null)RunTime(gameObject,new RunTimeEventArgs(timeDelta,moveTime)); timeDelta += (Time.deltaTime);
} else {
if(RunTime != null)RunTime(gameObject,new RunTimeEventArgs(timeDelta,moveTime));
if(OverMove != null)OverMove(gameObject); StopMove2D();
}
} public void StopMove2D()
{
Destroy(this);
isMoveRuning = false;
} }

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

OverMove事件在运动结束的时候发生;

RunTime事件在运动的每一帧发生,runTime是运动进行了多长时间,totalTime是传进去的那个运动总时间;

两个事件都会把gameObject传过去,可以利用它做一些处理;

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 mv2d = Move2D.createMove_Bounce3(gameObject,new Vector3(,,),5f,4f);
mv2d.OverMove += new Move2D.OverMoveEventHandler(overMove);
// mv2d.RunTime += new Move2D.RunTimeEventHandler(moveTime);
} private void overMove(GameObject gObj)
{
Debug.Log("结束移动");
} private void moveTime(GameObject gObj,Move2D.RunTimeEventArgs rte)
{
Debug.Log("还有"+(rte.totalTime-rte.runTime)+"秒结束");
}

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

我只是 抛砖引玉 具体的运动效果是要你项目需求来做的。

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

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

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

Unity利用AnimationCurve做物体的各种运动的更多相关文章

  1. Unity 利用NGUI做屏幕分辨率适配&plus;学习UIDraggablePanel的使用

    原地址:http://blog.sina.com.cn/s/blog_697b1b8c0101g2r4.html 大家使用unity,一定有看中其跨平台的强大功能,因此也难免会遇到不同屏幕分辨率适配的 ...

  2. Unity 利用NGUI2&period;6&period;3做技能冷却的CD效果

    NGUI非常强大我们今天来学习一下,如何利用NGUI做技能冷却的CD效果.先导入NGUI的插件.没有的话这里有啊NGUI2.6.3下载地址: http://vdisk.weibo.com/s/KLqn ...

  3. js 运动函数篇 &lpar;一&rpar; (匀速运动、缓冲运动、多物体运动、多物体不同值运动、多物体多值运动)层层深入

    前言:         本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽.         本篇文章为您分析一下原生JS写 匀速运动.缓冲运动.多物体运 ...

  4. &lbrack;我给Unity官方视频教程做中文字幕&rsqb;beginner Graphics – Lessons系列之网格Meshes

    [我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之网格Meshes 本篇分享一下第5个已完工的视频,即<beginner Graphics – ...

  5. &lbrack;我给Unity官方视频教程做中文字幕&rsqb;beginner Graphics – Lessons系列之材质了解Materials

    [我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之材质了解Materials 既上一篇分享了中文字幕的灯光介绍Lights后,本篇分享一下第3个已完工 ...

  6. &lbrack;我给Unity官方视频教程做中文字幕&rsqb;beginner Graphics – Lessons系列之灯光介绍Lights

    [我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之灯光介绍Lights 既上一篇分享了中文字幕的摄像机介绍Cameras后,本篇分享一下第2个已完工的 ...

  7. &lbrack;我给Unity官方视频教程做中文字幕&rsqb;beginner Graphics – Lessons系列之摄像机介绍Cameras

    [我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之摄像机介绍Cameras 最近得到一些Unity官方视频教程,一看全是纯英文的讲解,没有任何字幕或者 ...

  8. JavaScript 运动(缓冲运动,多物体运动 &comma;多物体多值运动&plus;回调机制)

    匀速运动   (当需要物体做匀速运动直接调用statMove函数) function startMove(dom,targetPosetion){ //dom : 运动对象,targetPositio ...

  9. 原生JavaScript运动功能系列(三):多物体多值运动

    多物体同时出发运动函数实现 多属性同步运动变化实现 一.多物同时触发运动函数实现 前面两个动画示例基本理解了动画的核心:位置变化和速度变化,操作的核心就是定时器分段叠加属性值.但是动画还是基于单个元素 ...

随机推荐

  1. Spark算上下基线

    def baseLine(sc: SparkContext): Unit = { println("--------------------baseLine start----------- ...

  2. struts2的包和命名空间

    struts2提供了命名空间的功能,主要是为了处理同一个WEB应用中包含同名Action的情形.struts2以命名空间的方式来管理Action,同一个命名空间里不能有同名的Action,不同的命名空 ...

  3. oschina数据库相关

    数据库相关 110数据库服务器 233NoSQL数据库 18MySQL衍生版 6开源XML数据库 311数据库管理工具 117数据库调整和优化 274数据库驱动程序 41数据库建模

  4. &lt&semi;转&gt&semi;shell经典&comma;shell十三问

    (注:关于变量概念,我们留到下两章才跟大家说明.) 好了,更多的关于 command line 的格式,以及 echo 命令的选项,就请您自行多加练习.运用了... ----------------- ...

  5. 目标指定法——S&period;M&period;A&period;R&period;T&period;

    一个有效的目标一定要是 具体的(Specific), 可测量的(Measureable), 可实现的(Attainable), 有现实意义的(Realistic), 以及有明确期限的(Time-bas ...

  6. css样式的书写顺序及原理——很重要!

    记得刚开始学习前端的时候,每次写css样式都是用到什么就在样式表后添加什么,完全没有考虑到样式属性的书写顺序对网页加载代码的影响.后来逐渐才知道正确的样式顺序不仅易于查看,并且也属于css样式优化的一 ...

  7. LeetCode算法题-Valid Perfect Square(Java实现-四种解法)

    这是悦乐书的第209次更新,第221篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第77题(顺位题号是367).给定正整数num,写一个函数,如果num是一个完美的正方形 ...

  8. 【HDU1848】Fibonacci again and again(博弈论)

    [HDU1848]Fibonacci again and again(博弈论) 题面 Hdu 你有三堆石子,每堆石子的个数是\(n,m,p\),你每次可以从一堆石子中取走斐波那契数列中一个元素等数量的 ...

  9. RabbitMQ基础介绍

    非原创,仅作为个人的学习资料,转自 anzhsoft http://blog.csdn.net/anzhsoft/article/details/19563091, 1. 历史 RabbitMQ是一个 ...

  10. 基于 Laravel 开发博客应用系列 —— 从测试开始(二):使用Gulp实现自动化测试

    3.使用 Gulp 进行 TDD(测试驱动开发) Gulp 是一个使用 JavaScript 编写的自动化构建工具.用于对前端通用任务(如最小化.压缩.编译)进行自动构建.Gulp 还可以用来监控源代 ...