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。

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

时间: 2024-11-13 03:44:58

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

[我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之摄像机介绍Cameras

[我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之摄像机介绍Cameras 最近得到一些Unity官方视频教程,一看全是纯英文的讲解,没有任何字幕或者讲稿之类的东西.虽然基本上看的懂,但很难听清其中一些细致的知识点.于是产生了做中文字幕的想法.本篇分享一下首个已完工的视频,即<beginner Graphics – Lessons系列之摄像机介绍Cameras>.听译.时间轴.压制者均为本人.请勿将视频用于非法目的. 优酷视频好像不太清晰,有需

[我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之灯光介绍Lights

[我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之灯光介绍Lights 既上一篇分享了中文字幕的摄像机介绍Cameras后,本篇分享一下第2个已完工的视频,即<beginner Graphics – Lessons系列之灯光介绍Lights>.听译.时间轴.压制者均为本人.请勿将视频用于非法目的. 有需要高清视频的同学麻烦点个赞并留下你的Email~ 有视频有真相 视频中的重点 类似现实世界,Unity中用灯光照亮场景 没有灯光,场景中的物体在

[我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之纹理Textures

[我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之纹理Textures 本篇分享一下第6个已完工的视频,即<beginner Graphics – Lessons系列之纹理Textures>.听译.时间轴.压制者均为本人.请勿将视频用于非法目的. 有需要高清视频的同学麻烦点个赞并留下你的Email~ 有视频有真相 视频中的重点 纹理是一个图片文件 Unity有多种使用纹理的方式最常见的方式是把纹理赋给网格的基础纹理属性使网格具有纹理的表面 纹理

[我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之网格Meshes

[我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之网格Meshes 本篇分享一下第5个已完工的视频,即<beginner Graphics – Lessons系列之网格Meshes>.听译.时间轴.压制者均为本人.请勿将视频用于非法目的. 有需要高清视频的同学麻烦点个赞并留下你的Email~ 有视频有真相 视频中的重点 Unity中的物体是由3D网格或多边形网格构成的 无论是角色只在一个平面上的简单的2D游戏 还是一个使用精灵(贴图)的复杂的粒

[我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之材质了解Materials

[我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之材质了解Materials 既上一篇分享了中文字幕的灯光介绍Lights后,本篇分享一下第3个已完工的视频,即<beginner Graphics – Lessons系列之材质了解Materials>.听译.时间轴.压制者均为本人.请勿将视频用于非法目的. 有需要高清视频的同学麻烦点个赞并留下你的Email~ 最近本人在搬家,上网机会少,回复较慢请谅解 有视频有真相 视频中的重点 Unity中的

每个程序员和设计师必做的10项运动

每个程序员和设计师必做的10项运动 分类 程序员人生 程序员和设计师大部分时间都坐在电脑前.有效的锻炼有助于他们更好地工作. 传统的: 当坐在电脑桌前的时候 脚触地. 双手在肘部弯曲. 打字时手应搁在桌子上. 键盘和鼠标应在触手可及的地方. 显示屏应在视线水平上,不高不低. 光线最好应来自上方.即光线应该从天花板上照下来. 每隔20分钟远眺.可降低眼睛长时间盯着近距离物体产生的疲劳. 鼠标和手差不多大小. 使用全尺寸符合人体工学的键盘.我个人比较喜欢Microsoft和Logitech这两个品牌

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

多物体同时出发运动函数实现 多属性同步运动变化实现 一.多物同时触发运动函数实现 前面两个动画示例基本理解了动画的核心:位置变化和速度变化,操作的核心就是定时器分段叠加属性值.但是动画还是基于单个元素实现,如果将前面封装的动画实现方法同时触发我可以肯定的告诉你会有bug,我们先来写一个示例看看这个bug是什么?示例需求是有三个div同时居于浏览器左侧,当鼠标进入div时,当前div的宽度变宽,鼠标离开时,宽度也已动画状态恢复. //html <div></div> <div&

手把手教你用深度学习做物体检测(六):YOLOv2介绍

本文接着上一篇<手把手教你用深度学习做物体检测(五):YOLOv1介绍>文章,介绍YOLOv2在v1上的改进.有些性能度量指标术语看不懂没关系,后续会有通俗易懂的关于性能度量指标的介绍文章. YOLOv2 论文:< YOLO9000: Better, Faster, Stronger> 地址:  https://arxiv.org/pdf/1612.08242v1.pdf yolov2和v1的区别 引入了Batch Normalization  有一定的正则化效果,可以减轻过拟合,

Java基础-继承 利用接口做参数,写个计算器,能完成+-*/运算

38.利用接口做参数,写个计算器,能完成+-*/运算 (1)定义一个接口Compute含有一个方法int computer(int n,int m); (2)设计四个类分别实现此接口,完成+-*/运算 (3)设计一个类UseCompute,含有方法: public void useCom(Compute com, int one, int two) 此方法要求能够:1.用传递过来的对象调用computer方法完成运算 2.输出运算的结果 (4)设计一个测试类,调用UseCompute中的方法us