ParticlePath.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. using System;
  4. [DisallowMultipleComponent]
  5. public class ParticlePath : MonoBehaviour
  6. {
  7. //Winspy
  8. [HideInInspector]
  9. public bool IsBezier = false;
  10. [HideInInspector]
  11. public int BezierSmoothSens = 20;
  12. [HideInInspector]
  13. public float CameraWaitTime = 0;
  14. float cameraWaitTick = 0;
  15. private List<Vector3> BezierPoints = new List<Vector3>();
  16. float cameraMoveTick = 0;
  17. Vector3[] path;
  18. Vector3[] vector3s;
  19. [HideInInspector]
  20. public bool IsCameraFollow = false;
  21. [HideInInspector]
  22. public float CameraSpeed = 10f;
  23. [HideInInspector]
  24. public bool IsApprove = false;
  25. [HideInInspector]
  26. public bool IsPath = false;
  27. [HideInInspector]
  28. public List<Vector3> Waypoints;
  29. [HideInInspector]
  30. public bool IsHideInInspector = false;
  31. [HideInInspector]
  32. public ParticleSystem PS;
  33. [HideInInspector]
  34. public float Speed = 2;
  35. private ParticleSystem.MainModule _psmm;
  36. private float _oldSpeed;
  37. private void Awake()
  38. {
  39. if (!PS || Waypoints.Count <= 0)
  40. {
  41. IsApprove = false;
  42. IsPath = false;
  43. return;
  44. }
  45. //创建贝塞尔曲线的路径点(而不是实时计算)
  46. //if (IsBezier)
  47. MakeBezierPoints();
  48. _psmm = PS.main;
  49. _oldSpeed = Speed;
  50. if (IsBezier)
  51. _psmm.startLifetime = BezierPoints.Count * Speed;
  52. else
  53. _psmm.startLifetime = Waypoints.Count * Speed;
  54. _psmm.simulationSpace = ParticleSystemSimulationSpace.Custom;
  55. _psmm.customSimulationSpace = transform;
  56. transform.localRotation = Quaternion.identity;
  57. //Camera.main.transform.position = new Vector3(0, 0, 0);
  58. //if (IsCameraFollow)
  59. // Camera.main.transform.position = transform.position;
  60. cameraWaitTick = 0;
  61. }
  62. /// <summary>
  63. /// 外部调用初始化
  64. /// </summary>
  65. public void InitPath(ParticleSystem ps, List<Vector3> pathPoints, float speed = 2f, bool useBezier = false)
  66. {
  67. if (ps == null || pathPoints == null || pathPoints.Count == 0)
  68. {
  69. Debug.LogError("ParticleSystem or PathPoints are null/empty!");
  70. return;
  71. }
  72. PS = ps;
  73. Waypoints = pathPoints;
  74. Speed = speed;
  75. IsBezier = useBezier;
  76. // 初始化 MainModule
  77. _psmm = PS.main;
  78. _psmm.simulationSpace = ParticleSystemSimulationSpace.Custom;
  79. _psmm.customSimulationSpace = transform;
  80. }
  81. private void Update()
  82. {
  83. if (IsApprove && IsPath)
  84. {
  85. //直线模式
  86. if (IsBezier == false)
  87. {
  88. MoveParticles(Waypoints);
  89. if (IsCameraFollow)
  90. MoveLineCamera();
  91. }
  92. else
  93. {
  94. MoveParticles(BezierPoints);
  95. if (IsCameraFollow)
  96. MoveBezierCamera();
  97. }
  98. }
  99. }
  100. void MoveParticles(List<Vector3> movePoints)
  101. {
  102. ParticleSystem.Particle[] ps = new ParticleSystem.Particle[PS.particleCount];
  103. int pCount = PS.GetParticles(ps);
  104. if (_oldSpeed != Speed)
  105. {
  106. _oldSpeed = Speed;
  107. _psmm.startLifetime = movePoints.Count * Speed;
  108. }
  109. for (int i = 0; i < pCount; i++)
  110. {
  111. float proportion = (ps[i].startLifetime - ps[i].remainingLifetime) / ps[i].startLifetime;
  112. int index = Mathf.FloorToInt(proportion * movePoints.Count);
  113. if (index >= 0 && index < movePoints.Count - 1)
  114. {
  115. Vector3 direction = movePoints[index + 1] - movePoints[index];
  116. ps[i].velocity = direction * (1.0f / Speed) * (1.0f / transform.localScale.x);
  117. }
  118. else
  119. {
  120. ps[i].remainingLifetime = 0;
  121. }
  122. }
  123. PS.SetParticles(ps, pCount);
  124. }
  125. public void ChangeSegmentToLine()
  126. {
  127. IsBezier = false;
  128. _psmm.startLifetime = Waypoints.Count * Speed;
  129. }
  130. public void ChangeSegmentToBezier()
  131. {
  132. IsBezier = true;
  133. _psmm.startLifetime = BezierPoints.Count * Speed;
  134. }
  135. void MoveBezierCamera()
  136. {
  137. if (cameraWaitTick<CameraWaitTime )
  138. {
  139. cameraWaitTick += Time.deltaTime;
  140. return;
  141. }
  142. cameraMoveTick = cameraMoveTick + Time.deltaTime / CameraSpeed;
  143. Vector3 currPt = Interp(vector3s, cameraMoveTick);
  144. Vector3 nextPt = Interp(vector3s, cameraMoveTick + 0.03f);
  145. Camera.main.transform.position = currPt;
  146. Camera.main.transform.LookAt(nextPt);
  147. if (cameraMoveTick > 1)
  148. cameraMoveTick = 0;
  149. }
  150. void MoveLineCamera()
  151. {
  152. if (cameraWaitTick < CameraWaitTime)
  153. {
  154. cameraWaitTick += Time.deltaTime;
  155. return;
  156. }
  157. cameraMoveTick = cameraMoveTick + Time.deltaTime / CameraSpeed;
  158. Vector3 currPt = LineInterp(path, cameraMoveTick);
  159. Vector3 nextPt = LineInterp(path, cameraMoveTick + 0.03f);
  160. Camera.main.transform.position = currPt;
  161. Camera.main.transform.LookAt(nextPt);
  162. if (cameraMoveTick > 1)
  163. cameraMoveTick = 0;
  164. }
  165. void MakeBezierPoints()
  166. {
  167. path = Waypoints.ToArray();
  168. vector3s = PathControlPointGenerator(path);
  169. BezierPoints.Clear();
  170. int SmoothAmount = Waypoints.Count * BezierSmoothSens;
  171. for (int i = 1; i <= SmoothAmount; i++)
  172. {
  173. float pm = (float)i / SmoothAmount;
  174. //Debug.Log(pm);
  175. Vector3 currPt = Interp(vector3s, pm);
  176. BezierPoints.Add(currPt);
  177. }
  178. }
  179. /// <summary>
  180. ///
  181. /// </summary>
  182. /// <param name="offset"></param>
  183. public void SetCameraPosition(float offset)
  184. {
  185. cameraMoveTick = offset;
  186. }
  187. //贝塞尔曲线函数
  188. public Vector3[] PathControlPointGenerator(Vector3[] path)
  189. {
  190. Vector3[] suppliedPath;
  191. Vector3[] vector3s;
  192. //create and store path points:
  193. suppliedPath = path;
  194. //populate calculate path;
  195. int offset = 2;
  196. vector3s = new Vector3[suppliedPath.Length + offset];
  197. Array.Copy(suppliedPath, 0, vector3s, 1, suppliedPath.Length);
  198. //populate start and end control points:
  199. //vector3s[0] = vector3s[1] - vector3s[2];
  200. vector3s[0] = vector3s[1] + (vector3s[1] - vector3s[2]);
  201. vector3s[vector3s.Length - 1] = vector3s[vector3s.Length - 2] + (vector3s[vector3s.Length - 2] - vector3s[vector3s.Length - 3]);
  202. //is this a closed, continuous loop? yes? well then so let's make a continuous Catmull-Rom spline!
  203. if (vector3s[1] == vector3s[vector3s.Length - 2])
  204. {
  205. Vector3[] tmpLoopSpline = new Vector3[vector3s.Length];
  206. Array.Copy(vector3s, tmpLoopSpline, vector3s.Length);
  207. tmpLoopSpline[0] = tmpLoopSpline[tmpLoopSpline.Length - 3];
  208. tmpLoopSpline[tmpLoopSpline.Length - 1] = tmpLoopSpline[2];
  209. vector3s = new Vector3[tmpLoopSpline.Length];
  210. Array.Copy(tmpLoopSpline, vector3s, tmpLoopSpline.Length);
  211. }
  212. return (vector3s);
  213. }
  214. public Vector3 Interp(Vector3[] pts, float t)
  215. {
  216. int numSections = pts.Length - 3;
  217. int currPt = Mathf.Min(Mathf.FloorToInt(t * (float)numSections), numSections - 1);
  218. float u = t * (float)numSections - (float)currPt;
  219. Vector3 a = pts[currPt];
  220. Vector3 b = pts[currPt + 1];
  221. Vector3 c = pts[currPt + 2];
  222. Vector3 d = pts[currPt + 3];
  223. return .5f * (
  224. (-a + 3f * b - 3f * c + d) * (u * u * u)
  225. + (2f * a - 5f * b + 4f * c - d) * (u * u)
  226. + (-a + c) * u
  227. + 2f * b
  228. );
  229. }
  230. public Vector3 LineInterp(Vector3[] pts, float t)
  231. {
  232. int numSections = pts.Length - 1;// - 3;
  233. int currPt = Mathf.Min(Mathf.FloorToInt(t * (float)numSections), numSections - 1);
  234. float u = t * (float)numSections - (float)currPt;
  235. currPt += 1;
  236. if (currPt > 0)
  237. return Vector3.Lerp(pts[currPt - 1], pts[currPt], u);
  238. else
  239. return Vector3.Lerp(transform.position, pts[currPt], u);
  240. }
  241. }