MovePath.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. [ExecuteInEditMode]
  5. public class MovePath : MonoBehaviour
  6. {
  7. public int id;
  8. public int slices = 10;
  9. public LinePointInfo[] points = new LinePointInfo[0];
  10. public float[] approximateLengths;
  11. Dictionary<LogicTransform, Coroutine> moveCoroutines = new Dictionary<LogicTransform, Coroutine> ();
  12. public void StartMoveTarget (LogicTransform target, float speed, bool hasStartMove, bool lookAtForward, Vector3 offset)
  13. {
  14. if (moveCoroutines.ContainsKey (target)) {
  15. StopCoroutine (moveCoroutines [target]);
  16. moveCoroutines.Remove (target);
  17. }
  18. moveCoroutines.Add (target, StartCoroutine (DoMoveTarget (target, speed, hasStartMove, lookAtForward, offset)));
  19. }
  20. IEnumerator DoMoveTarget (LogicTransform target, float speed, bool hasStartMove, bool lookAtForward, Vector3 offset)
  21. {
  22. LinePointInfo[] offsetPoints = GetOffsetPoints (offset.x);
  23. if (offsetPoints == null)
  24. yield break;
  25. int currentSegmentIdx = 0;
  26. float distanceInCurrentSegment = 0;
  27. bool moveEnd = false;
  28. Vector3 startPosition = offsetPoints[0].point;
  29. if (hasStartMove) {
  30. if (!target.Position.FEqual (startPosition, 1e-2f)) {
  31. target.LookAt (startPosition);
  32. while (!target.Position.FEqual (startPosition, 1e-2f)) {
  33. yield return 1;
  34. target.SetPosition (Vector3.MoveTowards (target.Position, startPosition, speed * Time.deltaTime));
  35. }
  36. }
  37. }
  38. target.SetPosition (startPosition);
  39. while (!moveEnd) {
  40. yield return 1;
  41. distanceInCurrentSegment += Time.deltaTime * speed;
  42. while (distanceInCurrentSegment > approximateLengths [currentSegmentIdx]) {
  43. if (currentSegmentIdx >= approximateLengths.Length - 1) {
  44. distanceInCurrentSegment = approximateLengths [currentSegmentIdx];
  45. moveEnd = true;
  46. break;
  47. } else {
  48. distanceInCurrentSegment -= approximateLengths [currentSegmentIdx];
  49. currentSegmentIdx++;
  50. }
  51. }
  52. int last = approximateLengths.Length;
  53. int start = currentSegmentIdx;
  54. int end = currentSegmentIdx + 1;
  55. int prev = start == 0 ? start : (points [start].smoothOut ? start - 1 : start);
  56. int next = end == last ? end : (points [end].smoothIn ? end + 1 : end);
  57. Vector3 targetposition = Interpolate.CatmullRom (offsetPoints [prev].point, offsetPoints [start].point, offsetPoints [end].point,
  58. offsetPoints [next].point, distanceInCurrentSegment, approximateLengths [currentSegmentIdx]);
  59. target.SetPosition (targetposition);
  60. if (lookAtForward) {
  61. Vector3 dir = Interpolate.GetDir (offsetPoints [prev].point, offsetPoints [start].point, offsetPoints [end].point,
  62. offsetPoints [next].point, distanceInCurrentSegment, approximateLengths [currentSegmentIdx]);
  63. Vector3 right = Vector3.Cross (dir, Vector3.up);
  64. Vector3 up = Vector3.Cross (right, dir);
  65. target.LookForward (dir, up);
  66. }
  67. }
  68. moveCoroutines.Remove (target);
  69. }
  70. public void StopMoveTarget (LogicTransform target)
  71. {
  72. if (moveCoroutines.ContainsKey (target)) {
  73. StopCoroutine (moveCoroutines [target]);
  74. moveCoroutines.Remove (target);
  75. }
  76. }
  77. public bool IsTargetMove (LogicTransform target)
  78. {
  79. return moveCoroutines.ContainsKey (target);
  80. }
  81. public bool HasTargetMove {
  82. get {
  83. return moveCoroutines.Count > 0;
  84. }
  85. }
  86. // public Vector3 GetStartPositionWithOffset (Vector3 offset)
  87. // {
  88. // if (points.Length > 1) {
  89. // Vector3 forward = (points [1].point - points [0].point).normalized;
  90. // Vector3 right = Vector3.Cross (forward, Vector3.up);
  91. // return points [0].point + right * offset.x;
  92. // } else
  93. // return points [0].point;
  94. // }
  95. public Vector3 GetEndPositionWithOffset (Vector3 offset)
  96. {
  97. if (points == null || points.Length == 0)
  98. return Vector3.zero;
  99. if (points.Length == 1)
  100. return points [0].point;
  101. else
  102. return points [points.Length - 1].point +
  103. Vector3.Cross ((points [points.Length - 1].point - points [points.Length - 2].point), Vector3.up).SetY (0).normalized * offset.x;
  104. }
  105. LinePointInfo[] GetOffsetPoints(float offsetValue)
  106. {
  107. if (points == null || points.Length == 0)
  108. return null;
  109. if (points.Length == 1) {
  110. LinePointInfo[] result = new LinePointInfo[1];
  111. result [0] = points [0];
  112. return result;
  113. } else {
  114. LinePointInfo[] result = new LinePointInfo[points.Length];
  115. points.CopyTo (result, 0);
  116. for (int i = 0; i < result.Length - 1; i++) {
  117. int start = i;
  118. int end = start + 1;
  119. int prev = start == 0 ? start : start - 1;
  120. Vector3 forward = (points [end].point - points [prev].point);
  121. Vector3 right = Vector3.Cross (forward, Vector3.up).SetY (0).normalized;
  122. result [start].point = points [start].point + right * offsetValue;
  123. }
  124. //last point
  125. result [result.Length - 1].point = points [result.Length - 1].point + Vector3.Cross ((points [result.Length - 1].point - points [result.Length - 2].point), Vector3.up).SetY (0).normalized * offsetValue;
  126. return result;
  127. }
  128. }
  129. void UpdateApproximateLengths ()
  130. {
  131. if (points.Length < 2)
  132. return;
  133. if (approximateLengths == null || approximateLengths.Length != points.Length - 1)
  134. approximateLengths = new float[points.Length - 1];
  135. for (int i = 0; i < approximateLengths.Length; i++)
  136. approximateLengths [i] = 0;
  137. IEnumerable<Vector3> sequence = Interpolate.NewCatmullRomByPointInfo (points, slices, false);
  138. IEnumerator<Vector3> iter = sequence.GetEnumerator ();
  139. Vector3 prev = Vector3.zero;
  140. bool hasPrev = false;
  141. int idx = 0;
  142. while (iter.MoveNext ()) {
  143. if (hasPrev) {
  144. float distance = Vector3.Distance (prev, iter.Current);
  145. approximateLengths [(idx - 1) / (slices + 1)] += distance;
  146. }
  147. prev = iter.Current;
  148. hasPrev = true;
  149. idx++;
  150. }
  151. }
  152. // public Vector3 GetEndPositionWithOffset (Vector3 offset)
  153. // {
  154. // return points [points.Length - 1].point + offset;
  155. // }
  156. //
  157. // bool IsPositionCloseTo (Vector3 v1, Vector3 v2)
  158. // {
  159. // return (v1 - v2).sqrMagnitude < 0.001f;
  160. // }
  161. #if UNITY_EDITOR
  162. public Vector3[] mDrawOffsets;
  163. void OnDrawGizmos ()
  164. {
  165. Gizmos.color = Color.red;
  166. DrawPath (points);
  167. if (mDrawOffsets != null) {
  168. Gizmos.color = Color.green;
  169. for (int i = 0; i < mDrawOffsets.Length; i++)
  170. DrawPath (GetOffsetPoints(mDrawOffsets [i].x));
  171. }
  172. if (points != null)
  173. for (int i = 0; i < points.Length; i++)
  174. DrawPoint (points [i].point);
  175. }
  176. void DrawPoint (Vector3 pos)
  177. {
  178. Gizmos.color = Color.blue;
  179. Gizmos.DrawLine (pos + Vector3.forward * 0.1f, pos + Vector3.back * 0.1f);
  180. Gizmos.DrawLine (pos + Vector3.right * 0.1f, pos + Vector3.left * 0.1f);
  181. }
  182. void DrawPath (LinePointInfo[] pointInfos)
  183. {
  184. if (pointInfos.Length < 2 || approximateLengths == null)
  185. return;
  186. int currentSegmentIdx = 0;
  187. float distanceInCurrentSegment = 0;
  188. int last = approximateLengths.Length;
  189. int start = currentSegmentIdx;
  190. int end = currentSegmentIdx + 1;
  191. int prev = start == 0 ? start : (pointInfos [start].smoothOut ? start - 1 : start);
  192. int next = end == last ? end : (pointInfos [end].smoothIn ? end + 1 : end);
  193. Vector3 lastPos = Interpolate.CatmullRom (pointInfos [prev].point, pointInfos [start].point, pointInfos [end].point,
  194. pointInfos [next].point, distanceInCurrentSegment, approximateLengths [currentSegmentIdx]);
  195. // up = Vector3.Cross (right, forward);
  196. // lastPos += (right * offset.x + up * offset.y + forward * offset.z);
  197. bool isEnd = false;
  198. while (!isEnd) {
  199. distanceInCurrentSegment += 0.1f;
  200. while (distanceInCurrentSegment > approximateLengths [currentSegmentIdx]) {
  201. if (currentSegmentIdx >= approximateLengths.Length - 1) {
  202. distanceInCurrentSegment = approximateLengths [currentSegmentIdx];
  203. isEnd = true;
  204. break;
  205. } else {
  206. distanceInCurrentSegment -= approximateLengths [currentSegmentIdx];
  207. currentSegmentIdx++;
  208. }
  209. }
  210. start = currentSegmentIdx;
  211. end = currentSegmentIdx + 1;
  212. prev = start == 0 ? start : (pointInfos [start].smoothOut ? start - 1 : start);
  213. next = end == last ? end : (pointInfos [end].smoothIn ? end + 1 : end);
  214. Vector3 nextPos = Interpolate.CatmullRom (pointInfos [prev].point, pointInfos [start].point, pointInfos [end].point,
  215. pointInfos [next].point, distanceInCurrentSegment, approximateLengths [currentSegmentIdx]);
  216. Gizmos.DrawLine (lastPos, nextPos);
  217. lastPos = nextPos;
  218. }
  219. }
  220. void Update ()
  221. {
  222. if (points == null)
  223. points = new LinePointInfo[transform.childCount];
  224. if (points != null) {
  225. for (int i = 0; i < points.Length; i++) {
  226. if (points [i].bindTrasform == null)
  227. points [i].bindTrasform = transform.Find ("point" + i);
  228. if (points [i].bindTrasform == null) {
  229. GameObject go = new GameObject ("point" + i);
  230. go.transform.SetParent (transform);
  231. go.transform.position = points [i].point;
  232. points [i].bindTrasform = go.transform;
  233. } else {
  234. points [i].point = points [i].bindTrasform.position;
  235. if (points [i].bindTrasform.name.CompareTo ("point" + i) != 0)
  236. points [i].bindTrasform.name = "point" + i;
  237. }
  238. }
  239. }
  240. UpdateApproximateLengths ();
  241. }
  242. #endif
  243. //#if UNITY_EDITOR
  244. //
  245. // public bool testMove = false;
  246. // public Transform testMoveTarget;
  247. // public Vector3 testMoveOffset = Vector3.zero;
  248. // public float testMoveSpeed = 10f;
  249. //
  250. // int lastPointLength = 0;
  251. // int lastChildCount = 0;
  252. //
  253. // void OnDrawGizmos()
  254. // {
  255. // if (lastChildCount != transform.childCount)
  256. // SyncPointsWithChild();
  257. // else if (lastPointLength != points.Length)
  258. // SyncChildWithPoints();
  259. //
  260. // lastChildCount = transform.childCount;
  261. // lastPointLength = points.Length;
  262. //
  263. // if (points.Length < 2)
  264. // return;
  265. //
  266. // SyncPointPosition();
  267. //
  268. // approximateLengths = new float[points.Length - 1];
  269. //
  270. // IEnumerable<Vector3> sequence = Interpolate.NewCatmullRomByPointInfo(points, slices, false);
  271. // IEnumerator<Vector3> iter = sequence.GetEnumerator();
  272. // Vector3 prev = Vector3.zero;
  273. // bool hasPrev = false;
  274. // int idx = 0;
  275. // while (iter.MoveNext())
  276. // {
  277. // if (idx % (slices + 1) == 0)
  278. // {
  279. // Gizmos.color = Color.green;
  280. // Gizmos.DrawSphere(iter.Current, 0.1f);
  281. // }
  282. //
  283. // if (hasPrev)
  284. // {
  285. // Gizmos.color = Color.red;
  286. // Gizmos.DrawLine(prev, iter.Current);
  287. // float distance = Vector3.Distance(prev, iter.Current);
  288. // //Log.E("idx : {0}", idx);
  289. // approximateLengths[(idx - 1) / (slices + 1)] += distance;
  290. // }
  291. //
  292. // prev = iter.Current;
  293. // hasPrev = true;
  294. // idx++;
  295. // }
  296. //
  297. // if (testMove)
  298. // {
  299. // StartMoveTarget(new LogicTransform(testMoveTarget), testMoveSpeed, true, true, testMoveOffset);
  300. // testMove = false;
  301. // }
  302. //
  303. // if (testMoveTarget != null)
  304. // {
  305. // Gizmos.color = Color.cyan;
  306. // Gizmos.DrawSphere(testMoveTarget.position, 0.2f);
  307. // //Gizmos.DrawLine(testMoveTarget.position, testMoveTarget.position + testMoveTarget.forward);
  308. // }
  309. // }
  310. //
  311. // void SyncChildWithPoints()
  312. // {
  313. // List<Transform> bindChilds = new List<Transform>();
  314. // List<Transform> unbindChilds = new List<Transform>();
  315. // for (int i = 0; i < points.Length; i++)
  316. // {
  317. // if (bindChilds.Contains(points[i].bindTrasform))
  318. // points[i].bindTrasform = null;
  319. //
  320. // if (points[i].bindTrasform == null)
  321. // {
  322. // points[i].bindTrasform = new GameObject().transform;
  323. // points[i].bindTrasform.SetParent(transform);
  324. // points[i].bindTrasform.localPosition = Vector3.zero;
  325. // points[i].bindTrasform.localEulerAngles = Vector3.zero;
  326. // }
  327. //
  328. // points[i].bindTrasform.name = "point" + i;
  329. // bindChilds.Add(points[i].bindTrasform);
  330. // }
  331. //
  332. // for (int i = 0; i < transform.childCount; i++)
  333. // {
  334. // if (!bindChilds.Contains(transform.GetChild(i)))
  335. // unbindChilds.Add(transform.GetChild(i));
  336. // }
  337. //
  338. // for (int i = 0; i < unbindChilds.Count; i++)
  339. // {
  340. // unbindChilds[i].gameObject.DestroyImmediate();
  341. // }
  342. // }
  343. //
  344. // void SyncPointsWithChild()
  345. // {
  346. // LinePointInfo[] newpoints = new LinePointInfo[transform.childCount];
  347. // for (int i = 0; i < newpoints.Length; i++)
  348. // {
  349. // if (i < points.Length)
  350. // newpoints[i] = points[i];
  351. // else
  352. // newpoints[i] = new LinePointInfo();
  353. // newpoints[i].bindTrasform = transform.GetChild(i);
  354. // newpoints[i].bindTrasform.name = "point" + i;
  355. // }
  356. // points = newpoints;
  357. // }
  358. //
  359. // void SyncPointPosition()
  360. // {
  361. // for (int i = 0; i < points.Length; i++)
  362. // {
  363. // if (points[i].bindTrasform != null)
  364. // points[i].point = points[i].bindTrasform.position;
  365. // //points[i].smoothIn = true;
  366. // //points[i].smoothOut = true;
  367. // }
  368. // }
  369. //
  370. //#endif
  371. }