SlopeCollider.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. using System;
  2. using UnityEngine;
  3. public enum SlopeDirection
  4. {
  5. Level,
  6. Uphill,
  7. Downhill
  8. }
  9. internal struct SlopeHit
  10. {
  11. internal float distance;
  12. internal bool even;
  13. internal float angle;
  14. internal SlopeHit(float distance, bool even, float angle)
  15. {
  16. this.distance = distance;
  17. this.even = even;
  18. this.angle = angle;
  19. }
  20. public override string ToString()
  21. {
  22. return $"SlopeHit(distance = {distance}, even = {even}, angle = {angle})";
  23. }
  24. }
  25. public class SlopeCollider : MonoBehaviour
  26. {
  27. public int collisionLayer = 1;
  28. public Transform rearWheelContactPoint;
  29. public Transform frontWheelContactPoint;
  30. private const float THRESHOLD = 0f;
  31. private Transform t;
  32. private float distRwFw;
  33. private SlopeDirection currentSlope = SlopeDirection.Level;
  34. private void Start()
  35. {
  36. t = transform;
  37. distRwFw = Mathf.Abs(frontWheelContactPoint.localPosition.z - rearWheelContactPoint.localPosition.z);
  38. }
  39. private void FixedUpdate()
  40. {
  41. var fwContact = frontWheelContactPoint.position;
  42. var rwContact = rearWheelContactPoint.position;
  43. var fwHit = DrawRay(fwContact);
  44. var rwHit = DrawRay(rwContact);
  45. if ((fwHit?.even ?? true) && (rwHit?.even ?? true)) return;
  46. if (rwHit.HasValue)
  47. {
  48. var rwHitVal = rwHit.Value;
  49. if (rwHitVal.angle > 0.01f)
  50. {
  51. t.RotateAround(fwContact, frontWheelContactPoint.right, -rwHitVal.angle);
  52. }
  53. /*if (rwHitVal.even)
  54. {
  55. //begin of slope
  56. Rotate(rwHitVal.distance, rwHitVal.distance - (fwHit?.distance ?? 0f), fwContact, rwContact);
  57. }*/
  58. }
  59. if (fwHit.HasValue)
  60. {
  61. var fwHitVal = fwHit.Value;
  62. if (fwHitVal.angle > 0.01f)
  63. {
  64. t.RotateAround(rwContact, rearWheelContactPoint.right, -fwHitVal.angle);
  65. }
  66. /*if (fwHitVal.even)
  67. {
  68. //end of slope
  69. Rotate(fwHitVal.distance, fwHitVal.distance - (rwHit?.distance ?? 0f), fwContact, rwContact);
  70. }*/
  71. }
  72. Debug.Log("----Slope Collider----");
  73. Debug.Log($"\tfwHit: {fwHit}");
  74. Debug.Log($"\trwHit: {rwHit}");
  75. }
  76. private void Rotate(float dist, float distDif, Vector3 fwContact, Vector3 rwContact)
  77. {
  78. var angle = Mathf.Atan(dist / distRwFw) * Mathf.Rad2Deg;
  79. if (distDif < -THRESHOLD) //rwDist > fwDist
  80. {
  81. //rear wheel in the air -> rotate around front wheel -> make it go uphill
  82. currentSlope = SlopeDirection.Uphill;
  83. t.RotateAround(fwContact, frontWheelContactPoint.right, -angle);
  84. }
  85. else if (dist > THRESHOLD)
  86. {
  87. //front wheel in the air -> rotate around rear wheel
  88. currentSlope = SlopeDirection.Downhill;
  89. t.RotateAround(rwContact, rearWheelContactPoint.right, angle);
  90. }
  91. }
  92. private SlopeHit? DrawRay(Vector3 start)
  93. {
  94. var layerMask = 1 << collisionLayer;
  95. RaycastHit hit;
  96. // Does the ray intersect any objects excluding the player layer
  97. if (Physics.Raycast(start, -t.up, out hit, 20f, layerMask))
  98. {
  99. Debug.DrawRay(start, -t.up * hit.distance, Color.green);
  100. Debug.DrawRay(hit.point, hit.normal, Color.blue);
  101. var isUneven = hit.collider.gameObject.CompareTag(StreetPartMetaTag.TAG_UNEVEN);
  102. var first = -(-t.up * hit.distance);
  103. var second = (hit.normal);
  104. var angle = Mathf.Acos(Vector3.Dot(first, second) / first.magnitude * second.magnitude) * Mathf.Rad2Deg;
  105. Debug.Log("Dot Product: " + Vector3.Dot(first, second));
  106. Debug.Log("Angle: " + angle);
  107. return new SlopeHit(hit.distance, !isUneven, angle);
  108. }
  109. Debug.DrawRay(start, -t.up * 20f, Color.red);
  110. return null;
  111. }
  112. }