1.效果1

2.效果2

看了上面的贝塞尔曲线的公式,大家应该能想到unity中的一个函数Lerp吧,我们根据上一个文章来看:
1. 一阶贝塞尔曲线公式是这样的
- List<Vector3> pointsList=new List<Vector3>() {Vector3.zero,Vector3.one };
-
- //一阶贝塞尔
- public Vector3 FirstOrderBezier(float t)
- {
- Vector3 a = pointsList[0];
- Vector3 b = pointsList[1];
- return a + (b - a) * t;
- }
如果我们使用Lerp来写的话是这样:
- List<Vector3> pointsList=new List<Vector3>() {Vector3.zero,Vector3.one };
-
- //一阶贝塞尔
- public Vector3 FirstOrderBezierLerp(float t)
- {
- Vector3 a = pointsList[0];
- Vector3 b = pointsList[1];
- return Vector3.Lerp(a,b,t);
- }
2. 二阶贝塞尔曲线
- List<Vector3> pointsList=new List<Vector3>() {Vector3.zero,Vector3.one, new Vector3(2,2,2)};
-
- //二阶贝塞尔
- public Vector3 SecondOrderBezierLerp(float t)
- {
- Vector3 a = pointsList[0];
- Vector3 b = pointsList[1];
- Vector3 c = pointsList[2];
-
- Vector3 aa = a + (b - a) * t;
- Vector3 bb = b + (c - b) * t;
- return aa + (bb - aa) * t;
- }
Lerp
- //二阶贝塞尔
- public Vector3 SecondOrderBezierLerp(float t)
- {
- Vector3 a = pointsList[0];
- Vector3 b = pointsList[1];
- Vector3 c = pointsList[2];
-
- Vector3 aa = Vector3.Lerp(a, b, t);
- Vector3 bb = Vector3.Lerp(b, c, t);
- return Vector3.Lerp(aa, bb, t);
- }
好的根据这个规律我们写一个n阶贝塞尔曲线
- #region N阶贝塞尔曲线
- public List<Vector3> bezierPointList;
- //存储计算的贝塞尔曲线结果
- List<Vector3> calculateBezierPointList=new List<Vector3>();
- public Vector3 NOrderBezierLerp(float t)
- {
- //点为空或为0
- if (bezierPointList==null|| bezierPointList.Count<=0)
- return Vector3.zero;
-
- //点为1
- if (bezierPointList.Count == 1)
- return bezierPointList[0];
-
- Vector3 result = Vector3.zero; //返回的结果
-
- //列表赋值
- calculateBezierPointList = bezierPointList;
-
- //当列表的值大于等于2时执行
- while (calculateBezierPointList.Count>=2)
- {
- List<Vector3> pointList = new List<Vector3>();
-
- for (int i = 0; i < calculateBezierPointList.Count-1; i++)
- {
- Vector3 posA = calculateBezierPointList[i];
- Vector3 posB = calculateBezierPointList[i+1];
- pointList.Add(Vector3.Lerp(posA, posB,t));
- }
- //将计算好的贝塞尔曲线列表赋值给calculateBezierPointList
- calculateBezierPointList = pointList;
- }
-
- //最终计算后列表中只有1个点
- result = calculateBezierPointList[0];
- return result;
- }
- #endregion
然后我们用LineRenderer组件来测试这个N阶贝塞尔曲线是否管用
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- /// <summary>
- /// N阶贝塞尔曲线测试
- /// </summary>
- public class N_OrderBezierLerpTest : MonoBehaviour
- {
- LineRenderer line;
-
- void Start()
- {
- line = GetComponent<LineRenderer>();
- line.positionCount = 100;
- }
-
- void Update()
- {
- //实时创建贝塞尔曲线点
- for (int i = 1; i < line.positionCount + 1; i++)
- {
- Vector3 Bezierposition = N_OrderBezierLerp(i * 0.01f);
- line.SetPosition(i - 1, Bezierposition);
- }
- }
-
- #region N阶贝塞尔曲线
- public List<Vector3> bezierPointList;
- //存储计算的贝塞尔曲线结果
- List<Vector3> calculateBezierPointList=new List<Vector3>();
- public Vector3 N_OrderBezierLerp(float t)
- {
- //点为空或为0
- if (bezierPointList==null|| bezierPointList.Count<=0)
- return Vector3.zero;
-
- //点为1
- if (bezierPointList.Count == 1)
- return bezierPointList[0];
-
- Vector3 result = Vector3.zero; //返回的结果
-
- //列表赋值
- calculateBezierPointList = bezierPointList;
-
- //当列表的值大于等于2时执行
- while (calculateBezierPointList.Count>=2)
- {
- List<Vector3> pointList = new List<Vector3>();
-
- for (int i = 0; i < calculateBezierPointList.Count-1; i++)
- {
- Vector3 posA = calculateBezierPointList[i];
- Vector3 posB = calculateBezierPointList[i+1];
- pointList.Add(Vector3.Lerp(posA, posB,t));
- }
- //将计算好的贝塞尔曲线列表赋值给calculateBezierPointList
- calculateBezierPointList = pointList;
- }
-
- //最终计算后列表中只有1个点
- result = calculateBezierPointList[0];
- return result;
- }
- #endregion
-
-
- }
场景布局:
运行程序来看看效果:

看这样我们就可以随心所欲的创建多种曲线效果了。
1.Bezier.cs
贝塞尔曲线脚本,里面记录了N阶贝塞尔曲线公式
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- /// <summary>
- /// 贝塞尔曲线工具脚本
- /// </summary>
- public class Bezier
- {
- //存储计算的贝塞尔曲线结果
- static List<Vector3> calculateBezierPointList = new List<Vector3>();
- /// <summary>
- /// N阶贝塞尔曲线
- /// </summary>
- /// <param name="bezierPointList">贝塞尔曲线列表</param>
- /// <param name="t">t值</param>
- /// <returns></returns>
- public static Vector3 N_OrderBezierLerp(List<Vector3> bezierPointList, float t)
- {
- //点为空或为0
- if (bezierPointList == null || bezierPointList.Count <= 0)
- return Vector3.zero;
-
- //点为1
- if (bezierPointList.Count == 1)
- return bezierPointList[0];
-
- Vector3 result = Vector3.zero; //返回的结果
-
- //列表赋值
- calculateBezierPointList = bezierPointList;
-
- //当列表的值大于等于2时执行
- while (calculateBezierPointList.Count >= 2)
- {
- List<Vector3> pointList = new List<Vector3>();
-
- for (int i = 0; i < calculateBezierPointList.Count - 1; i++)
- {
- Vector3 posA = calculateBezierPointList[i];
- Vector3 posB = calculateBezierPointList[i + 1];
- pointList.Add(Vector3.Lerp(posA, posB, t));
- }
- //将计算好的贝塞尔曲线列表赋值给calculateBezierPointList
- calculateBezierPointList = pointList;
- }
-
- //最终计算后列表中只有1个点
- result = calculateBezierPointList[0];
- return result;
- }
- }
2. item.cs
此脚本是要挂载在图片上,用于记录当前在曲线的位置
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine.UI;
- using UnityEngine;
-
- /// <summary>
- /// 图片ietm
- /// </summary>
- public class Item : MonoBehaviour
- {
- float bezierT;
- SpriteRenderer m_Img;
-
- //封装
- public float BezierT { get => bezierT; set => bezierT = value; }
-
- /// <summary>
- /// 修改图片精灵
- /// </summary>
- /// <param name="sprite"></param>
- public void SetImageSprite(Sprite sprite)
- {
- //image为空时初始化
- if (m_Img==null)
- m_Img = transform.GetChild(0).GetComponent<SpriteRenderer>();
-
- m_Img.sprite = sprite;
- }
-
- }
3.BezierController.cs
此脚本控制物体在曲线的排列,以及鼠标控制拖动等功能
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine.UI;
- using UnityEngine;
-
- //贝塞尔曲线控制
- public class BezierController : MonoBehaviour
- {
- //此处距离最好是0或1 否则速度过快可能导致图片串位
- [Header("首尾消失距离")]
- [Range(0, 0.5f)]
- [SerializeField] float leftDis = 0;
- [Range(0.5f, 1f)]
- [SerializeField] float rightDis = 1;
-
- [Header("控制鼠标拖动物体速度")]
- [SerializeField] float speed = 1;
-
- [Header("物体容器")]
- public Transform content;//容器
-
- LineRenderer line;
-
- [Header("图片精灵列表,贝塞尔曲线点位")]
- public List<Sprite> spriteList;
- public List<Vector3> bezierPointList;
-
- void Start()
- {
- line = GetComponent<LineRenderer>();
- line.positionCount = 100;
-
- //初始化图片布局
- InitItem();
- }
-
- Vector2 oldPos;
- void Update()
- {
- //生成贝塞尔曲线点 LineRender
- Bezier_Creat();
-
- //按下I按键初始化item布局
- if (Input.GetKey(KeyCode.I))
- InitItem(); //初始化
-
- #region 鼠标拖动控制左右移动
- if (Input.GetMouseButtonDown(0))
- {
- oldPos = Input.mousePosition;
- }
-
- if (Input.GetMouseButton(0))
- {
- Vector2 pos = new Vector2(Input.mousePosition.x - oldPos.x, Input.mousePosition.y - oldPos.y);
- for (int i = 0; i < content.childCount; i++)
- {
- Item obj = content.GetChild(i).GetComponent<Item>();
- objMove(pos, obj);
- }
- oldPos = Input.mousePosition;
- }
- #endregion
-
- }
-
- #region 初始化item平均布局
- public void InitItem()
- {
- Debug.Log("初始化");
-
- //计算物体在曲线中的t值(间距)
- float space = Mathf.Abs(rightDis - leftDis) / content.childCount;
- Debug.Log(space);
-
- //循环初始化
- for (int i = 0; i < content.childCount; i++)
- {
- Item obj = content.GetChild(i).GetComponent<Item>();
- obj.BezierT = leftDis + (i * space);
- Vector3 _pos = Bezier.N_OrderBezierLerp(bezierPointList, obj.BezierT);
- obj.transform.position = new Vector3(_pos.x, _pos.y, -1);
- SetImageSprite(1, obj); //修改图片
- }
- }
- #endregion
-
- #region 物体移动
- string valueSt;
- string[] valueArray;
- void objMove(Vector2 pos, Item obj)
- {
- float value = (pos.x * speed * Time.deltaTime) / Screen.width;
- obj.BezierT += value;
-
-
- if (obj.BezierT > rightDis)
- {
- valueSt = obj.BezierT.ToString();
- valueArray = valueSt.Split('.');
- valueSt = "0." + valueArray[valueArray.Length - 1];
- obj.BezierT = float.Parse(valueSt);
- }
-
- if (obj.BezierT <= leftDis)
- {
- valueSt = obj.BezierT.ToString();
- valueArray = valueSt.Split('.');
- valueSt = "0." + valueArray[valueArray.Length - 1];
- obj.BezierT = rightDis - Mathf.Abs(float.Parse(valueSt));
- }
-
-
- if (obj.BezierT >= rightDis)
- {
- int index = pos.x > 0 ? 1 : -1;
- obj.BezierT = leftDis;
- //替换图片
- SetImageSprite(index, obj); //修改图片
- }
-
- Vector3 _pos = Bezier.N_OrderBezierLerp(bezierPointList, obj.BezierT);
- obj.transform.position = new Vector3(_pos.x, _pos.y, -1);
-
- }
-
- #endregion
-
- #region 图片替换
- int currentIndex = -1;
- /// <summary>
- /// 图片替换
- /// </summary>
- /// <param name="dir">移动方向</param>
- /// <param name="item">要替换的图片物体</param>
- void SetImageSprite(int dir, Item item)
- {
- if (dir > 0)
- {
- currentIndex++;
- //超出图片列表最大值 等于0
- if (currentIndex > spriteList.Count - 1)
- currentIndex = 0;
- }
-
- if (dir < 0)
- {
- currentIndex--;
- //超出图片列表最小值 等于列表最后一个
- if (currentIndex < 0)
- currentIndex = spriteList.Count - 1;
- }
-
- //修改item图片
- item.SetImageSprite(spriteList[currentIndex]);
-
- }
- #endregion
-
- #region 生成贝塞尔曲线
- /// <summary>
- /// 生成贝塞尔曲线Line
- /// </summary>
- private void Bezier_Creat()
- {
- for (int i = 1; i < line.positionCount + 1; i++)
- {
- Vector3 Bezierposition = Bezier.N_OrderBezierLerp(bezierPointList, i*0.01f);
- line.SetPosition(i - 1, Bezierposition);
- }
- }
- #endregion
-
-
- }
脚本中我都加了很详细的注释,如果有问题或者不懂的可以在评论交流指正。
版本:2019.4.4f1
http://链接:https://pan.baidu.com/s/1bwFY80igzlOZQ7QlYx8aHg 提取码:syq1