SlopeCollider.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. using UnityEngine;
  2. namespace Wheels
  3. {
  4. public enum RotateDirection
  5. {
  6. Unknown,
  7. None,
  8. Forward,
  9. Backward
  10. }
  11. internal struct SlopeHit
  12. {
  13. internal float distance;
  14. internal bool even;
  15. internal float angle;
  16. internal Vector3 hitPoint;
  17. internal SlopeHit(float distance, bool even, float angle, Vector3 hitPoint)
  18. {
  19. this.distance = distance;
  20. this.even = even;
  21. this.angle = angle;
  22. this.hitPoint = hitPoint;
  23. }
  24. public override string ToString()
  25. {
  26. return $"SlopeHit(distance = {distance}, even = {even}, angle = {angle})";
  27. }
  28. }
  29. public class SlopeCollider : MonoBehaviour
  30. {
  31. private const float THRESHOLD = 0.003f;
  32. public int collisionLayer = 1;
  33. public SphereCollider rearWheelCollider;
  34. public SphereCollider frontWheelCollider;
  35. public Transform bike;
  36. private RotateDirection currentRotateDirection = RotateDirection.Unknown;
  37. private float distRwFw;
  38. private Transform frontWheelContactPoint;
  39. private Transform rearWheelContactPoint;
  40. private void Start()
  41. {
  42. frontWheelContactPoint = frontWheelCollider.transform;
  43. rearWheelContactPoint = rearWheelCollider.transform;
  44. distRwFw = Mathf.Abs(frontWheelContactPoint.localPosition.z - rearWheelContactPoint.localPosition.z);
  45. }
  46. private void FixedUpdate()
  47. {
  48. var fwContact = frontWheelContactPoint.position;
  49. var rwContact = rearWheelContactPoint.position;
  50. var fwHit = DrawRay(fwContact);
  51. var rwHit = DrawRay(rwContact);
  52. if (!fwHit.HasValue || !rwHit.HasValue) return;
  53. //Debug.Log("----Slope Collider----");
  54. //Debug.Log($"\tfwHit: {fwHit}");
  55. //Debug.Log($"\trwHit: {rwHit}");
  56. var fw = fwHit.Value;
  57. var rw = rwHit.Value;
  58. var fwDist = fw.distance;
  59. var rwDist = rw.distance;
  60. var distDif = fwDist - rwDist;
  61. if (fwDist >= THRESHOLD && rwDist >= THRESHOLD)
  62. {
  63. var deltaY = fwDist <= rwDist ? fwDist : rwDist;
  64. bike.Translate(0, -deltaY, 0);
  65. //Debug.Log($"Translated {-deltaY} on y");
  66. }
  67. else if (fw.distance >= THRESHOLD)
  68. {
  69. var angle = Mathf.Atan(fw.distance / distRwFw) * Mathf.Rad2Deg;
  70. //Debug.Log($"Rotating {angle} deg");
  71. bike.RotateAround(rearWheelContactPoint.position, rearWheelContactPoint.right, angle);
  72. }
  73. else if (rw.distance >= THRESHOLD)
  74. {
  75. var angle = Mathf.Atan(rw.distance / distRwFw) * Mathf.Rad2Deg;
  76. bike.RotateAround(frontWheelContactPoint.position, frontWheelContactPoint.right, -angle);
  77. //Debug.Log($"Rotating {-angle} deg");
  78. }
  79. //if ((fwHit?.even ?? true) && (rwHit?.even ?? true)) return;
  80. /*var distFw = fwHit?.distance ?? 0f;
  81. var distRw = rwHit?.distance ?? 0f;
  82. var distDif = distFw - distRw;
  83. if (fwHit.HasValue && rwHit.HasValue)
  84. {
  85. var fw = fwHit.Value;
  86. var rw = rwHit.Value;
  87. if (!fw.even && rw.even)
  88. {
  89. if (fw.hitPoint.y > rw.hitPoint.y && currentRotateDirection != RotateDirection.Forward)
  90. {
  91. currentRotateDirection = RotateDirection.Backward;
  92. }else if (currentRotateDirection != RotateDirection.Backward)
  93. {
  94. currentRotateDirection = RotateDirection.Forward;
  95. }
  96. }else if (fw.even && !rw.even)
  97. {
  98. if (fw.hitPoint.y > rw.hitPoint.y && currentRotateDirection != RotateDirection.Backward)
  99. {
  100. currentRotateDirection = RotateDirection.Forward;
  101. }
  102. else if(currentRotateDirection != RotateDirection.Forward)
  103. {
  104. currentRotateDirection = RotateDirection.Backward;
  105. }
  106. }
  107. else
  108. {
  109. currentRotateDirection = RotateDirection.None; //TODO: maybe not
  110. }
  111. }
  112. else
  113. {
  114. if (distDif < -THRESHOLD && currentRotateDirection != RotateDirection.Forward)
  115. {
  116. currentRotateDirection = RotateDirection.Backward;
  117. }else if (distDif > THRESHOLD && currentRotateDirection != RotateDirection.Backward)
  118. {
  119. currentRotateDirection = RotateDirection.Forward;
  120. }
  121. else
  122. {
  123. currentRotateDirection = RotateDirection.None;
  124. }
  125. }
  126. Debug.Log("CurrentRotateDirection = " + currentRotateDirection);
  127. Debug.Log("----Slope Collider----");
  128. Debug.Log($"\tfwHit: {fwHit}");
  129. Debug.Log($"\trwHit: {rwHit}");
  130. if (currentRotateDirection == RotateDirection.Backward) //rwDist > fwDist
  131. {
  132. //rear wheel in the air -> rotate around front wheel -> make it go uphill
  133. var angle = Mathf.Atan(distRw / distRwFw) * Mathf.Rad2Deg;
  134. bike.RotateAround(fwContact, frontWheelContactPoint.right, -angle);
  135. }
  136. else if (currentRotateDirection == RotateDirection.Forward)
  137. {
  138. //front wheel in the air -> rotate around rear wheel
  139. var angle = Mathf.Atan(distFw / distRwFw) * Mathf.Rad2Deg;
  140. bike.RotateAround(rwContact, rearWheelContactPoint.right, angle);
  141. }
  142. /*if (rwHit.HasValue)
  143. {
  144. var rwHitVal = rwHit.Value;
  145. if (rwHitVal.angle > 0.01f)
  146. {
  147. t.RotateAround(fwContact, frontWheelContactPoint.right, -rwHitVal.angle);
  148. }
  149. /*if (rwHitVal.even)
  150. {
  151. //begin of slope
  152. Rotate(rwHitVal.distance, rwHitVal.distance - (fwHit?.distance ?? 0f), fwContact, rwContact);
  153. }
  154. }
  155. if (fwHit.HasValue)
  156. {
  157. var fwHitVal = fwHit.Value;
  158. if (fwHitVal.angle > 0.01f)
  159. {
  160. t.RotateAround(rwContact, rearWheelContactPoint.right, -fwHitVal.angle);
  161. }
  162. /*if (fwHitVal.even)
  163. {
  164. //end of slope
  165. Rotate(fwHitVal.distance, fwHitVal.distance - (rwHit?.distance ?? 0f), fwContact, rwContact);
  166. }
  167. }*/
  168. }
  169. private SlopeHit? DrawRay(Vector3 start)
  170. {
  171. var layerMask = 1 << collisionLayer;
  172. RaycastHit hit;
  173. // Does the ray intersect any objects excluding the player layer
  174. if (Physics.Raycast(start, -bike.up, out hit, 20f, layerMask))
  175. {
  176. var up = bike.up;
  177. Debug.DrawRay(start, -up * hit.distance, Color.green);
  178. //Debug.DrawRay(hit.point, hit.normal, Color.blue);
  179. var isUneven = hit.collider.gameObject.CompareTag(StreetPartMetaTag.TAG_UNEVEN);
  180. var first = -(-up * hit.distance);
  181. var second = hit.normal;
  182. var angle = Mathf.Acos(Vector3.Dot(first, second) / first.magnitude * second.magnitude) * Mathf.Rad2Deg;
  183. //Debug.Log("Dot Product: " + Vector3.Dot(first, second));
  184. //Debug.Log("Angle: " + angle);
  185. return new SlopeHit(hit.distance, !isUneven, angle, hit.point);
  186. }
  187. if (Physics.Raycast(start, bike.up, out hit, 20f, layerMask))
  188. {
  189. var up = bike.up;
  190. Debug.DrawRay(start, -up * hit.distance, Color.green);
  191. //Debug.DrawRay(hit.point, hit.normal, Color.blue);
  192. var isUneven = hit.collider.gameObject.CompareTag(StreetPartMetaTag.TAG_UNEVEN);
  193. var first = -(-up * hit.distance);
  194. var second = hit.normal;
  195. var angle = Mathf.Acos(Vector3.Dot(first, second) / first.magnitude * second.magnitude) * Mathf.Rad2Deg;
  196. //Debug.Log("Dot Product: " + Vector3.Dot(first, second));
  197. //Debug.Log("Angle: " + angle);
  198. return new SlopeHit(-hit.distance, !isUneven, angle, hit.point);
  199. }
  200. //Debug.DrawRay(start, -t.up * 20f, Color.red);
  201. return null;
  202. }
  203. }
  204. }