unity 实现物体沿指定的平滑曲线移动(通过贝塞尔曲线实现)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yu1368072332/article/details/82531891

在实际项目开发中,为了实现某种动画或者特效,策划都会要求让物体实现沿编辑的轨迹进行移动,今天这里就讲一下如何让物体沿可编辑的路线进行移动,这里主要是通过贝塞尔曲线实现。

首先要了解贝塞尔曲线的基础知识及原理,具体可参考改链接:

http://www.cnblogs.com/jay-dong/archive/2012/09/26/2704188.html,具体就不做描述了。

这里的思路就是首先就是把关键节点保存起来,然后在通过贝塞尔的计算公式计算出两个节点之间的拟合点的集合,最后可以控制小球在运动的过程中通过走过的路径的长度作为下标,取出该长度下对应的坐标信息,从而实现小球沿规定路径移动。

下面是具体的代码实现:

首先是计算出指定轨迹的拟合点,保存到list中,就是只在初始化的时候计算出来,然后保存,后面可以一直沿用,如果是在运行边计算边使用计算量会偏大:

    #region 计算贝塞尔曲线的拟合点
    //初始化算出所有的点的信息
    void InitPoint()
    {
        //获取指定的点的信息
        Vector3[] pointPos = new Vector3[basePoint.Length];
        for (int i = 0; i < pointPos.Length; i++)
        {
            pointPos[i] = basePoint[i].transform.position;
        }
        GetTrackPoint(pointPos);
    }

    /// <summary>
    /// 根据设定节点 绘制指定的曲线
    /// </summary>
    /// <param name="track">所有指定节点的信息</param>
    public void GetTrackPoint(Vector3[] track)
    {
        Vector3[] vector3s = PathControlPointGenerator(track);
        int SmoothAmount = track.Length * baseCount;
        lineRender.positionCount = SmoothAmount;
        for (int i = 1; i < SmoothAmount; i++)
        {
            float pm = (float)i / SmoothAmount;
            Vector3 currPt = Interp(vector3s, pm);
            lineRender.SetPosition(i, currPt);
            lsPoint.Add(currPt);
        }
    }

    /// <summary>
    /// 计算所有节点以及控制点坐标
    /// </summary>
    /// <param name="path">所有节点的存储数组</param>
    /// <returns></returns>
    public 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);
    }


    /// <summary>
    /// 计算曲线的任意点的位置
    /// </summary>
    /// <param name="pos"></param>
    /// <param name="t"></param>
    /// <returns></returns>
    public Vector3 Interp(Vector3[] pos, float t)
    {
        int length = pos.Length - 3;
        int currPt = Mathf.Min(Mathf.FloorToInt(t * length), length - 1);
        float u = t * (float)length - (float)currPt;
        Vector3 a = pos[currPt];
        Vector3 b = pos[currPt + 1];
        Vector3 c = pos[currPt + 2];
        Vector3 d = pos[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
       );
    }
    #endregion

然后就是通过在update中移动小球,根据小球轨迹长度取出对应长度下的坐标信息赋值:

    void Start()
    {
        lineRender = gameObject.GetComponent<LineRenderer>();
        InitPoint();
    }

    void Update()
    {
        length += Time.deltaTime * speed;
        if (length >= lsPoint.Count - 1)
        {
            length = lsPoint.Count - 1;
        }
        sphere.transform.localPosition = lsPoint[(int)(length)];
    }

上述就是小球沿指定轨迹的具体思路。

工程链接:链接:https://pan.baidu.com/s/1h4FQNI1A9992k7T29J2GqQ 密码:mql1

想了解更多unity开发相关信息,可以关注下方公众号或者添加QQ交流群879354767,来分享学习游戏中的开发心得:

猜你喜欢

转载自blog.csdn.net/yu1368072332/article/details/82531891