• Unity之使用贝塞尔曲线制作图片轮播


    一、效果图

    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. 一阶贝塞尔曲线公式是这样的

    1. List<Vector3> pointsList=new List<Vector3>() {Vector3.zero,Vector3.one };
    2. //一阶贝塞尔
    3. public Vector3 FirstOrderBezier(float t)
    4. {
    5. Vector3 a = pointsList[0];
    6. Vector3 b = pointsList[1];
    7. return a + (b - a) * t;
    8. }

    如果我们使用Lerp来写的话是这样:

    1. List<Vector3> pointsList=new List<Vector3>() {Vector3.zero,Vector3.one };
    2. //一阶贝塞尔
    3. public Vector3 FirstOrderBezierLerp(float t)
    4. {
    5. Vector3 a = pointsList[0];
    6. Vector3 b = pointsList[1];
    7. return Vector3.Lerp(a,b,t);
    8. }

    2. 二阶贝塞尔曲线

    1. List<Vector3> pointsList=new List<Vector3>() {Vector3.zero,Vector3.one, new Vector3(2,2,2)};
    2. //二阶贝塞尔
    3. public Vector3 SecondOrderBezierLerp(float t)
    4. {
    5. Vector3 a = pointsList[0];
    6. Vector3 b = pointsList[1];
    7. Vector3 c = pointsList[2];
    8. Vector3 aa = a + (b - a) * t;
    9. Vector3 bb = b + (c - b) * t;
    10. return aa + (bb - aa) * t;
    11. }

    Lerp 

    1. //二阶贝塞尔
    2. public Vector3 SecondOrderBezierLerp(float t)
    3. {
    4. Vector3 a = pointsList[0];
    5. Vector3 b = pointsList[1];
    6. Vector3 c = pointsList[2];
    7. Vector3 aa = Vector3.Lerp(a, b, t);
    8. Vector3 bb = Vector3.Lerp(b, c, t);
    9. return Vector3.Lerp(aa, bb, t);
    10. }

    好的根据这个规律我们写一个n阶贝塞尔曲线

    1. #region N阶贝塞尔曲线
    2. public List<Vector3> bezierPointList;
    3. //存储计算的贝塞尔曲线结果
    4. List<Vector3> calculateBezierPointList=new List<Vector3>();
    5. public Vector3 NOrderBezierLerp(float t)
    6. {
    7. //点为空或为0
    8. if (bezierPointList==null|| bezierPointList.Count<=0)
    9. return Vector3.zero;
    10. //点为1
    11. if (bezierPointList.Count == 1)
    12. return bezierPointList[0];
    13. Vector3 result = Vector3.zero; //返回的结果
    14. //列表赋值
    15. calculateBezierPointList = bezierPointList;
    16. //当列表的值大于等于2时执行
    17. while (calculateBezierPointList.Count>=2)
    18. {
    19. List<Vector3> pointList = new List<Vector3>();
    20. for (int i = 0; i < calculateBezierPointList.Count-1; i++)
    21. {
    22. Vector3 posA = calculateBezierPointList[i];
    23. Vector3 posB = calculateBezierPointList[i+1];
    24. pointList.Add(Vector3.Lerp(posA, posB,t));
    25. }
    26. //将计算好的贝塞尔曲线列表赋值给calculateBezierPointList
    27. calculateBezierPointList = pointList;
    28. }
    29. //最终计算后列表中只有1个点
    30. result = calculateBezierPointList[0];
    31. return result;
    32. }
    33. #endregion

     然后我们用LineRenderer组件来测试这个N阶贝塞尔曲线是否管用

    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. /// <summary>
    5. /// N阶贝塞尔曲线测试
    6. /// </summary>
    7. public class N_OrderBezierLerpTest : MonoBehaviour
    8. {
    9. LineRenderer line;
    10. void Start()
    11. {
    12. line = GetComponent<LineRenderer>();
    13. line.positionCount = 100;
    14. }
    15. void Update()
    16. {
    17. //实时创建贝塞尔曲线点
    18. for (int i = 1; i < line.positionCount + 1; i++)
    19. {
    20. Vector3 Bezierposition = N_OrderBezierLerp(i * 0.01f);
    21. line.SetPosition(i - 1, Bezierposition);
    22. }
    23. }
    24. #region N阶贝塞尔曲线
    25. public List<Vector3> bezierPointList;
    26. //存储计算的贝塞尔曲线结果
    27. List<Vector3> calculateBezierPointList=new List<Vector3>();
    28. public Vector3 N_OrderBezierLerp(float t)
    29. {
    30. //点为空或为0
    31. if (bezierPointList==null|| bezierPointList.Count<=0)
    32. return Vector3.zero;
    33. //点为1
    34. if (bezierPointList.Count == 1)
    35. return bezierPointList[0];
    36. Vector3 result = Vector3.zero; //返回的结果
    37. //列表赋值
    38. calculateBezierPointList = bezierPointList;
    39. //当列表的值大于等于2时执行
    40. while (calculateBezierPointList.Count>=2)
    41. {
    42. List<Vector3> pointList = new List<Vector3>();
    43. for (int i = 0; i < calculateBezierPointList.Count-1; i++)
    44. {
    45. Vector3 posA = calculateBezierPointList[i];
    46. Vector3 posB = calculateBezierPointList[i+1];
    47. pointList.Add(Vector3.Lerp(posA, posB,t));
    48. }
    49. //将计算好的贝塞尔曲线列表赋值给calculateBezierPointList
    50. calculateBezierPointList = pointList;
    51. }
    52. //最终计算后列表中只有1个点
    53. result = calculateBezierPointList[0];
    54. return result;
    55. }
    56. #endregion
    57. }

    场景布局:

     运行程序来看看效果:

    看这样我们就可以随心所欲的创建多种曲线效果了。 

    三、使用贝塞尔曲线制作图片轮播

    1.Bezier.cs

    贝塞尔曲线脚本,里面记录了N阶贝塞尔曲线公式

    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. /// <summary>
    5. /// 贝塞尔曲线工具脚本
    6. /// </summary>
    7. public class Bezier
    8. {
    9. //存储计算的贝塞尔曲线结果
    10. static List<Vector3> calculateBezierPointList = new List<Vector3>();
    11. /// <summary>
    12. /// N阶贝塞尔曲线
    13. /// </summary>
    14. /// <param name="bezierPointList">贝塞尔曲线列表</param>
    15. /// <param name="t">t值</param>
    16. /// <returns></returns>
    17. public static Vector3 N_OrderBezierLerp(List<Vector3> bezierPointList, float t)
    18. {
    19. //点为空或为0
    20. if (bezierPointList == null || bezierPointList.Count <= 0)
    21. return Vector3.zero;
    22. //点为1
    23. if (bezierPointList.Count == 1)
    24. return bezierPointList[0];
    25. Vector3 result = Vector3.zero; //返回的结果
    26. //列表赋值
    27. calculateBezierPointList = bezierPointList;
    28. //当列表的值大于等于2时执行
    29. while (calculateBezierPointList.Count >= 2)
    30. {
    31. List<Vector3> pointList = new List<Vector3>();
    32. for (int i = 0; i < calculateBezierPointList.Count - 1; i++)
    33. {
    34. Vector3 posA = calculateBezierPointList[i];
    35. Vector3 posB = calculateBezierPointList[i + 1];
    36. pointList.Add(Vector3.Lerp(posA, posB, t));
    37. }
    38. //将计算好的贝塞尔曲线列表赋值给calculateBezierPointList
    39. calculateBezierPointList = pointList;
    40. }
    41. //最终计算后列表中只有1个点
    42. result = calculateBezierPointList[0];
    43. return result;
    44. }
    45. }

    2. item.cs

    此脚本是要挂载在图片上,用于记录当前在曲线的位置

    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine.UI;
    4. using UnityEngine;
    5. /// <summary>
    6. /// 图片ietm
    7. /// </summary>
    8. public class Item : MonoBehaviour
    9. {
    10. float bezierT;
    11. SpriteRenderer m_Img;
    12. //封装
    13. public float BezierT { get => bezierT; set => bezierT = value; }
    14. /// <summary>
    15. /// 修改图片精灵
    16. /// </summary>
    17. /// <param name="sprite"></param>
    18. public void SetImageSprite(Sprite sprite)
    19. {
    20. //image为空时初始化
    21. if (m_Img==null)
    22. m_Img = transform.GetChild(0).GetComponent<SpriteRenderer>();
    23. m_Img.sprite = sprite;
    24. }
    25. }

    3.BezierController.cs

    此脚本控制物体在曲线的排列,以及鼠标控制拖动等功能

    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine.UI;
    4. using UnityEngine;
    5. //贝塞尔曲线控制
    6. public class BezierController : MonoBehaviour
    7. {
    8. //此处距离最好是0或1 否则速度过快可能导致图片串位
    9. [Header("首尾消失距离")]
    10. [Range(0, 0.5f)]
    11. [SerializeField] float leftDis = 0;
    12. [Range(0.5f, 1f)]
    13. [SerializeField] float rightDis = 1;
    14. [Header("控制鼠标拖动物体速度")]
    15. [SerializeField] float speed = 1;
    16. [Header("物体容器")]
    17. public Transform content;//容器
    18. LineRenderer line;
    19. [Header("图片精灵列表,贝塞尔曲线点位")]
    20. public List<Sprite> spriteList;
    21. public List<Vector3> bezierPointList;
    22. void Start()
    23. {
    24. line = GetComponent<LineRenderer>();
    25. line.positionCount = 100;
    26. //初始化图片布局
    27. InitItem();
    28. }
    29. Vector2 oldPos;
    30. void Update()
    31. {
    32. //生成贝塞尔曲线点 LineRender
    33. Bezier_Creat();
    34. //按下I按键初始化item布局
    35. if (Input.GetKey(KeyCode.I))
    36. InitItem(); //初始化
    37. #region 鼠标拖动控制左右移动
    38. if (Input.GetMouseButtonDown(0))
    39. {
    40. oldPos = Input.mousePosition;
    41. }
    42. if (Input.GetMouseButton(0))
    43. {
    44. Vector2 pos = new Vector2(Input.mousePosition.x - oldPos.x, Input.mousePosition.y - oldPos.y);
    45. for (int i = 0; i < content.childCount; i++)
    46. {
    47. Item obj = content.GetChild(i).GetComponent<Item>();
    48. objMove(pos, obj);
    49. }
    50. oldPos = Input.mousePosition;
    51. }
    52. #endregion
    53. }
    54. #region 初始化item平均布局
    55. public void InitItem()
    56. {
    57. Debug.Log("初始化");
    58. //计算物体在曲线中的t值(间距)
    59. float space = Mathf.Abs(rightDis - leftDis) / content.childCount;
    60. Debug.Log(space);
    61. //循环初始化
    62. for (int i = 0; i < content.childCount; i++)
    63. {
    64. Item obj = content.GetChild(i).GetComponent<Item>();
    65. obj.BezierT = leftDis + (i * space);
    66. Vector3 _pos = Bezier.N_OrderBezierLerp(bezierPointList, obj.BezierT);
    67. obj.transform.position = new Vector3(_pos.x, _pos.y, -1);
    68. SetImageSprite(1, obj); //修改图片
    69. }
    70. }
    71. #endregion
    72. #region 物体移动
    73. string valueSt;
    74. string[] valueArray;
    75. void objMove(Vector2 pos, Item obj)
    76. {
    77. float value = (pos.x * speed * Time.deltaTime) / Screen.width;
    78. obj.BezierT += value;
    79. if (obj.BezierT > rightDis)
    80. {
    81. valueSt = obj.BezierT.ToString();
    82. valueArray = valueSt.Split('.');
    83. valueSt = "0." + valueArray[valueArray.Length - 1];
    84. obj.BezierT = float.Parse(valueSt);
    85. }
    86. if (obj.BezierT <= leftDis)
    87. {
    88. valueSt = obj.BezierT.ToString();
    89. valueArray = valueSt.Split('.');
    90. valueSt = "0." + valueArray[valueArray.Length - 1];
    91. obj.BezierT = rightDis - Mathf.Abs(float.Parse(valueSt));
    92. }
    93. if (obj.BezierT >= rightDis)
    94. {
    95. int index = pos.x > 0 ? 1 : -1;
    96. obj.BezierT = leftDis;
    97. //替换图片
    98. SetImageSprite(index, obj); //修改图片
    99. }
    100. Vector3 _pos = Bezier.N_OrderBezierLerp(bezierPointList, obj.BezierT);
    101. obj.transform.position = new Vector3(_pos.x, _pos.y, -1);
    102. }
    103. #endregion
    104. #region 图片替换
    105. int currentIndex = -1;
    106. /// <summary>
    107. /// 图片替换
    108. /// </summary>
    109. /// <param name="dir">移动方向</param>
    110. /// <param name="item">要替换的图片物体</param>
    111. void SetImageSprite(int dir, Item item)
    112. {
    113. if (dir > 0)
    114. {
    115. currentIndex++;
    116. //超出图片列表最大值 等于0
    117. if (currentIndex > spriteList.Count - 1)
    118. currentIndex = 0;
    119. }
    120. if (dir < 0)
    121. {
    122. currentIndex--;
    123. //超出图片列表最小值 等于列表最后一个
    124. if (currentIndex < 0)
    125. currentIndex = spriteList.Count - 1;
    126. }
    127. //修改item图片
    128. item.SetImageSprite(spriteList[currentIndex]);
    129. }
    130. #endregion
    131. #region 生成贝塞尔曲线
    132. /// <summary>
    133. /// 生成贝塞尔曲线Line
    134. /// </summary>
    135. private void Bezier_Creat()
    136. {
    137. for (int i = 1; i < line.positionCount + 1; i++)
    138. {
    139. Vector3 Bezierposition = Bezier.N_OrderBezierLerp(bezierPointList, i*0.01f);
    140. line.SetPosition(i - 1, Bezierposition);
    141. }
    142. }
    143. #endregion
    144. }

    脚本中我都加了很详细的注释,如果有问题或者不懂的可以在评论交流指正。

    三、原程序包

    版本:2019.4.4f1

    http://链接:https://pan.baidu.com/s/1bwFY80igzlOZQ7QlYx8aHg 提取码:syq1

  • 相关阅读:
    Nginx:http自动跳转到https
    理解ELMo 模型
    基于双级阈值及过零率的语音激活检测(VAD)
    实验四.路由器静态路由的配置
    KyLin离线安装OceanBase
    springboot毕设项目(智慧化工MES)质量管理系统f4i11(java+VUE+Mybatis+Maven+Mysql)
    为什么我认识的机械工程师都抱怨工资低?
    C:strcpy和strncpy的陷阱
    FPGA学习之状态机
    Linux 原子操作CAS与锁实现
  • 原文地址:https://blog.csdn.net/qq_42345116/article/details/124887818