物体曲线移动相关算法

收分简述:

  一般棋牌类游戏为了刺激玩家都会有较为好看的特效和惊艳的收分效果,所谓的收分就是金币出现到消失的过程,如下列3个收分效果

1.足球风云(先动画,再进入指定轨迹)

  

2.777_不知名游戏0

 3.777_不知名游戏1

3种收分效果 : 1.弧线 2.贝塞尔曲线 3.直线

弧线


这里我重点讲解一下弧线:

优点:1.运算量小 2.走线流畅

直接上代码:

/***************************************
Editor: Tason
Version: v1.0
Last Edit Date: 2018-XX-XX 
Tel: 328791554@qq.com
Function Doc: 

***************************************/

using UnityEngine;
using System.Collections;

namespace ZQFY
{
    public class MoneyCollectV : MonoBehaviour
    {
        private Vector3 m_cToO;
        private Vector3 m_eToO;

        private float m_totalTime;
        private float m_timer;

        private Vector3 m_center;

        private bool m_start;

        public delegate void DelegateAniEnd();
        public DelegateAniEnd delegateAniEnd;

        public AnimationCurve m_curve;

        void Update()
        {
            if (m_start)
            {
                float amount = 0;
                if (m_timer + Time.deltaTime >= m_totalTime)
                {
                    amount = 1;
                    m_start = false;

                }
                else
                {
                    m_timer += Time.deltaTime;
                    amount = m_timer / m_totalTime;
                }

                amount = m_curve.Evaluate(amount);

                transform.position = Vector3.Slerp(m_cToO, m_eToO, amount) + m_center;

                if (amount == 1)
                    if (delegateAniEnd != null)
                        delegateAniEnd();
            }
        }

        public void StartAni(Transform _t0, Transform _t1, float _range, float _totalTime, DelegateAniEnd _handler)
        {
            //计算圆心
            Vector3 m_orignalV = _t0.position;
            Vector3 m_endV = _t1.position;
            Vector3 v0 = m_endV - m_orignalV;
            m_center = Vector3.Cross(Vector3.forward, v0).normalized * _range + (m_orignalV + m_endV) * 0.5f;

            m_cToO = m_orignalV - m_center;
            m_eToO = m_endV - m_center;
            m_totalTime = _totalTime;

            m_start = true;
            m_timer = 0;

            delegateAniEnd = _handler;
        }
    }
}
View Code

讲解:

序:让物体通过插值从T0点弧线运动到T1点

1.通过 (t1 - t0) 得到v0向量(浅蓝色线)

2.通过 vector3.forward cross(叉乘) v0 得到指向圆心(Center)的方向向量,程序员通过该向量*长度 指定圆心所在位置。

3.在的到圆心以后既可以得到半径长度r,再通过圆心到t0,与t1点方向向量点渐变插值得到分量方向(紫色线),再乘以r得到分量位置,即可以得到一条完美的弧线。

理论上这条弧线可以通过到达各种位置

 贝塞尔曲线


优点:

  1.理论上可以走任意曲线。

  2.使用方便

缺点:

  1.移动的曲线定死的就那么几条,没办法编辑

  2.没办法进行插值

Example:

  

代码:

  

using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour
{

    //路径寻路中的所有点
    public Transform[] paths;

    //金钱
    public GameObject m_money;

    void Start()
    {
        Hashtable args = new Hashtable();
        //设置路径的点
        args.Add("path", paths);
        //设置类型为线性,线性效果会好一些。
        args.Add("easeType", iTween.EaseType.easeInOutQuad);

        args.Add("delay", 1.0f);
        args.Add("lookahead", 0.5f);
        //设置寻路的速度
        args.Add("speed", 10f);
        //是否先从原始位置走到路径中第一个点的位置
        args.Add("movetopath", true);
        //是否让模型始终面朝当面目标的方向,拐弯的地方会自动旋转模型
        //如果你发现你的模型在寻路的时候始终都是一个方向那么一定要打开这个
        args.Add("orienttopath", false);

        //让模型开始寻路   
        iTween.MoveTo(m_money, args);
    }

    void OnDrawGizmos()
    {
        //在scene视图中绘制出路径与线
        iTween.DrawLine(paths, Color.yellow);

        iTween.DrawPath(paths, Color.red);
    }

}
View Code

参数参考: https://blog.csdn.net/dingkun520wy/article/details/50476864

曲线参考:

贝塞尔曲线讲解:

http://www.cnblogs.com/jay-dong/archive/2012/09/26/2704188.html

https://www.cnblogs.com/fishyu/p/6817509.html

贝塞尔曲线2


 使用Itween的曲线插值算法(搬的代码)解决了上述无法控制曲线移动速率的问题。推荐☆☆☆☆☆ 

 而且这一套是脱离插件的哦~

曲线插值效果:

曲线插值代码:

using System;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 曲线测试
/// </summary>
public class CurveTest : MonoBehaviour
{
    //路点
    public GameObject[] m_pathTransList;

    //精度 点数 = m_accuracyCount * 路点.length
    public int m_accuracyCount = 20;

    //移动曲线
    public AnimationCurve m_curve;

    //金币物体
    public Transform m_money;

    //总时间
    public float m_totalTime = 2f;

    //计时器
    private float m_timer = 0;

    //是否移动
    private bool m_runFlag = false;

    //路点的坐标 - GUI渲染用
    private List<Vector3> m_guiLineList = new List<Vector3>();

    //路点坐标 - 实际使用
    private Vector3[] m_pathLineV3;

    //计算后的曲线点集
    private Vector3[] completeV3;

    //计算路点
    private void Awake()
    {
        //安全校验
        if (m_pathTransList.Length <= 1) return;

        m_pathLineV3 = new Vector3[m_pathTransList.Length];
        for (int i = 0; i < m_pathTransList.Length; ++i)
        {
            m_pathLineV3[i] = m_pathTransList[i].transform.position;
        }
        
        if (m_pathLineV3 != null && m_pathLineV3.Length > 1)
        {
            completeV3 = PathControlPointGenerator(m_pathLineV3);
        }

        m_timer = 0;
    }

    public void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            m_runFlag = true;
            m_timer = 0;
        }

        if (m_runFlag)
        {
            float amount = 0;
            if (m_timer + Time.deltaTime > m_totalTime)
            {
                m_runFlag = false;
                amount = 1;
            }
            else
            {
                m_timer += Time.deltaTime;
                amount = m_curve.Evaluate( m_timer / m_totalTime);
            }

            m_money.position = Interp(completeV3, amount);
        }
    }

    //渲染用
    void OnDrawGizmos()
    {
        //安全校验
        if (m_pathTransList.Length <= 1) return;

        m_guiLineList.Clear();
        for (int i = 0; i < m_pathTransList.Length; ++i)
        {
            m_guiLineList.Add(m_pathTransList[i].transform.position);
        }

        //画线与计算曲线点
        if (m_guiLineList != null && m_guiLineList.Count > 1)
        {
            DrawPathHelper(m_guiLineList.ToArray(), Color.red);
        }
    }

    //NGUI iTween.cs中的方法 不用深究
    public static Vector3[] PathControlPointGenerator(Vector3[] path)
    {
        Vector3[] suppliedPath;
        Vector3[] vector3s;
        
        suppliedPath = path;
        
        int offset = 2;
        vector3s = new Vector3[suppliedPath.Length + offset];
        Array.Copy(suppliedPath, 0, vector3s, 1, suppliedPath.Length);
        
        vector3s[0] = vector3s[1] + (vector3s[1] - vector3s[2]);
        vector3s[vector3s.Length - 1] = vector3s[vector3s.Length - 2] + (vector3s[vector3s.Length - 2] - vector3s[vector3s.Length - 3]);
        
        if (vector3s[1] == vector3s[vector3s.Length - 2])
        {
            Vector3[] tmpLoopSpline = new Vector3[vector3s.Length];
            Array.Copy(vector3s, tmpLoopSpline, vector3s.Length);
            tmpLoopSpline[0] = tmpLoopSpline[tmpLoopSpline.Length - 3];
            tmpLoopSpline[tmpLoopSpline.Length - 1] = tmpLoopSpline[2];
            vector3s = new Vector3[tmpLoopSpline.Length];
            Array.Copy(tmpLoopSpline, vector3s, tmpLoopSpline.Length);
        }

        return (vector3s);
    }

    //曲线插值函数
    public static Vector3 Interp(Vector3[] pts, float t)
    {
        int numSections = pts.Length - 3;
        int currPt = Mathf.Min(Mathf.FloorToInt(t * (float)numSections), numSections - 1);
        float u = t * (float)numSections - (float)currPt;

        Vector3 a = pts[currPt];
        Vector3 b = pts[currPt + 1];
        Vector3 c = pts[currPt + 2];
        Vector3 d = pts[currPt + 3];

        return .5f * (
            (-a + 3f * b - 3f * c + d) * (u * u * u)
            + (2f * a - 5f * b + 4f * c - d) * (u * u)
            + (-a + c) * u
            + 2f * b
        );
    }

    //画曲线
    private void DrawPathHelper(Vector3[] path, Color color)
    {
        Vector3[] v3 = PathControlPointGenerator(path);
        
        Vector3 prevPt = Interp(v3, 0);
        int SmoothAmount = path.Length * m_accuracyCount;

        iTween.DrawPath(path, Color.yellow);
        for (int i = 1; i <= SmoothAmount; i++)
        {
            float pm = (float)i / SmoothAmount;
            Vector3 currPt = Interp(v3, pm);

            Gizmos.color = color;
            Gizmos.DrawSphere(currPt, 0.01f);

            prevPt = currPt;
        }
    }
}
View Code

效果:

项目引用:

链接:https://pan.baidu.com/s/1oj-HcrS6nXjQc4HN5d_08w 密码:eqa0

原文地址:https://www.cnblogs.com/jwv5/p/9505863.html