来自于:游戏开发小学生
    效果如下图所示:
    1629186118(1).png
    1629186043(1).png
    主要是使用贝塞尔曲线实现类似杀戮尖塔的卡牌打出效果

    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. public class BezierArrows : MonoBehaviour
    5. {
    6. #region Public Fields
    7. [Tooltip("The Prefab of arrow head")]
    8. public GameObject ArrowHeadPrefab;
    9. [Tooltip("The Prefab of arrow node")]
    10. public GameObject ArrowNodePrefab;
    11. [Tooltip("the Number of arrow nodes")]
    12. public int arrowNodeNum;
    13. [Tooltip("The scale multiplier for arrow nodes")]
    14. public float scaleFactor = 1f;
    15. [Tooltip("Please do not assign values")]
    16. public Transform ShowObj;
    17. [Tooltip("Please do not assign values")]
    18. public bool IsActive = false;
    19. [Tooltip("Please do not assign values")]
    20. public Vector2 Position = Vector2.zero;
    21. #endregion
    22. #region Private Fields
    23. /// <summary>
    24. /// The position of P0 (The arrow emitter point)
    25. /// </summary>
    26. private RectTransform origin;
    27. /// <summary>
    28. /// The list of arrow nodes transform
    29. /// </summary>
    30. private List<RectTransform> arrowNodes = new List<RectTransform>();
    31. /// <summary>
    32. /// The list of control points
    33. /// </summary>
    34. private List<Vector2> controlPoints = new List<Vector2>();
    35. /// <summary>
    36. /// The factors to determine the position of control point P1,P2 控制曲线的形态
    37. /// </summary>
    38. private readonly List<Vector2> controlPointFactors = new List<Vector2>() { new Vector2(-0.3f, 0.8f), new Vector2(0.1f, 1.4f) };
    39. #endregion
    40. #region Private Methods
    41. /// <summary>
    42. /// Executes when the gameObject instantiates.
    43. /// </summary>
    44. private void Start()
    45. {
    46. //Gets position of the arrow emitter point
    47. this.origin = this.GetComponent<RectTransform>();
    48. for (int i = 0; i < this.arrowNodeNum; i++)
    49. {
    50. GameObject arrowNode = Instantiate(this.ArrowNodePrefab, ShowObj);
    51. arrowNode.SetActive(false);
    52. arrowNode.transform.SetAsFirstSibling();
    53. this.arrowNodes.Add(arrowNode.GetComponent<RectTransform>());
    54. }
    55. GameObject arrowHead = Instantiate(this.ArrowHeadPrefab, ShowObj);
    56. arrowHead.SetActive(false);
    57. arrowHead.transform.SetAsFirstSibling();
    58. this.arrowNodes.Add(arrowHead.GetComponent<RectTransform>());
    59. //Hides the arrow nodes
    60. this.arrowNodes.ForEach(a => a.GetComponent<RectTransform>().position = new Vector2(-1000, -1000));
    61. //Initializes the control points list
    62. for (int i = 0; i < 4; i++)
    63. {
    64. this.controlPoints.Add(Vector2.zero);
    65. }
    66. }
    67. /// <summary>
    68. /// Executes every frame
    69. /// </summary>
    70. private void Update()
    71. {
    72. //P0 is at the arrow emitter point
    73. //this.controlPoints[0] = new Vector2(this.origin.position.x, this.origin.position.y);
    74. this.controlPoints[0] = Position;
    75. Vector3 mouse = Camera.main.ScreenToWorldPoint(Input.mousePosition);
    76. //P3 is at the mouse position
    77. this.controlPoints[3] = new Vector2(mouse.x, mouse.y);
    78. //P1,P2 determines by P0 and P3
    79. //P1 = P0 + (P3 - P0) * Vector2(-0.3f, 0.8f)
    80. //P2 = P0 + (P3 - P0) * Vector2(0.1f, 1.4f)
    81. this.controlPoints[1] = this.controlPoints[0] + (this.controlPoints[3] - this.controlPoints[0]) * this.controlPointFactors[0];
    82. this.controlPoints[2] = this.controlPoints[0] + (this.controlPoints[3] - this.controlPoints[0]) * this.controlPointFactors[1];
    83. for (int i = 0; i < this.arrowNodes.Count; i++)
    84. {
    85. // Calculates t.
    86. var t = Mathf.Log(1f * i / (this.arrowNodes.Count - 1) + 1f, 2f);
    87. //Cubic Bezier curve
    88. //B(T) = (1 - t) ^ * P0 + 3 * (1 - t) ^ 2 * t * P1 + 3 * (1 - t) * t ^ 2 * P2 + t ^ 3 * P3
    89. this.arrowNodes[i].position = Mathf.Pow(1 - t, 3) * this.controlPoints[0] + 3 * Mathf.Pow(1 - t, 2) * t * this.controlPoints[1] + 3 * (1 - t) * Mathf.Pow(t, 2) * this.controlPoints[2] + Mathf.Pow(t, 3) * this.controlPoints[3];
    90. //Calculates rotations for each arrow node
    91. if (i > 0)
    92. {
    93. var euler = new Vector3(0, 0, Vector2.SignedAngle(Vector2.up, this.arrowNodes[i].position - this.arrowNodes[i - 1].position));
    94. this.arrowNodes[i].rotation = Quaternion.Euler(euler);
    95. }
    96. this.arrowNodes[i].gameObject.SetActive(IsActive);
    97. // Calculates scales for each arrow node
    98. //var scale = this.scaleFactor * (1f - 0.03f * (this.arrowNodes.Count - 1 - i));
    99. //this.arrowNodes[i].localScale = new Vector3(scale, scale, 1f);
    100. }
    101. //The first arrow nodes rotation
    102. this.arrowNodes[0].transform.rotation = this.arrowNodes[1].transform.rotation;
    103. }
    104. #endregion
    105. }