1.效果1
2.效果2
关于贝塞尔曲线的学习大家可以看这个文章进行学习https://blog.csdn.net/qq_39162826/article/details/119806754?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165313175716782395391583%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=165313175716782395391583&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-119806754-null-null.142^v10^pc_search_result_control_group,157^v4^control&utm_term=unity+%E8%B4%9D%E5%A1%9E%E5%B0%94%E6%9B%B2%E7%BA%BF&spm=1018.2226.3001.4187
看了上面的贝塞尔曲线的公式,大家应该能想到unity中的一个函数Lerp吧,我们根据上一个文章来看:
1. 一阶贝塞尔曲线公式是这样的
List pointsList=new List() {Vector3.zero,Vector3.one };
//一阶贝塞尔
public Vector3 FirstOrderBezier(float t)
{
Vector3 a = pointsList[0];
Vector3 b = pointsList[1];
return a + (b - a) * t;
}
如果我们使用Lerp来写的话是这样:
List pointsList=new List() {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 pointsList=new List() {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 bezierPointList;
//存储计算的贝塞尔曲线结果
List calculateBezierPointList=new List();
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 pointList = new List();
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;
///
/// N阶贝塞尔曲线测试
///
public class N_OrderBezierLerpTest : MonoBehaviour
{
LineRenderer line;
void Start()
{
line = GetComponent();
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 bezierPointList;
//存储计算的贝塞尔曲线结果
List calculateBezierPointList=new List();
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 pointList = new List();
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;
///
/// 贝塞尔曲线工具脚本
///
public class Bezier
{
//存储计算的贝塞尔曲线结果
static List calculateBezierPointList = new List();
///
/// N阶贝塞尔曲线
///
/// 贝塞尔曲线列表
/// t值
///
public static Vector3 N_OrderBezierLerp(List 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 pointList = new List();
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;
///
/// 图片ietm
///
public class Item : MonoBehaviour
{
float bezierT;
SpriteRenderer m_Img;
//封装
public float BezierT { get => bezierT; set => bezierT = value; }
///
/// 修改图片精灵
///
///
public void SetImageSprite(Sprite sprite)
{
//image为空时初始化
if (m_Img==null)
m_Img = transform.GetChild(0).GetComponent();
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 spriteList;
public List bezierPointList;
void Start()
{
line = GetComponent();
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- ();
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
- ();
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;
///
/// 图片替换
///
/// 移动方向
/// 要替换的图片物体
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 生成贝塞尔曲线
///
/// 生成贝塞尔曲线Line
///
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