No Description

CarController.cs 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. using UnityEngine;
  2. using UnityEngine.UI;
  3. using System.Collections.Generic;
  4. using System.Collections;
  5. using System;
  6. [Serializable]
  7. public class Wheel
  8. {
  9. public WheelCollider wheel;
  10. public bool motor;
  11. public bool steering;
  12. }
  13. [Serializable]
  14. public class Gear {
  15. public float ratio;
  16. public Sprite sprite;
  17. }
  18. public class CarController : MonoBehaviour
  19. {
  20. public GameObject checkForActive;
  21. public Image gearImage;
  22. public List<Wheel> wheels;
  23. public Speedometer speedometer = null;
  24. public Speedometer rpmMeter = null;
  25. public Vector3 shiftCentre = new Vector3(0.0f, -0.5f, 0.0f);
  26. public float torque = 100;
  27. public float brakeTorque = 2500F;
  28. public float maxSteerAngle = 30.0f;
  29. public float steerSpeed = 10.0f;
  30. public float shiftDelay = 1;
  31. public float shiftDownRPM = 1500.0f;
  32. public float shiftUpRPM = 2500.0f;
  33. public float maxRPM = 5500.0F;
  34. public float idleRPM = 500.0f;
  35. public bool automatic = false;
  36. public Gear[] gears;
  37. public int currentGear = 1;
  38. public bool steerAssist = false;
  39. public float steerSlowing = 0.01F;
  40. public float roadStiffness = 2;
  41. public float offRoadStiffness = 1;
  42. float nextShift = 0;
  43. float[] efficiencyTable = { 0.6f, 0.65f, 0.7f, 0.75f, 0.8f, 0.85f, 0.9f, 1.0f, 1.0f, 0.95f, 0.80f, 0.70f, 0.60f, 0.5f, 0.45f, 0.40f, 0.36f, 0.33f, 0.30f, 0.20f, 0.10f, 0.05f };
  44. float efficiencyTableStep = 250.0f;
  45. protected Rigidbody rb = null;
  46. protected virtual void Start() {
  47. if (GetComponent<Rigidbody>() != null)
  48. {
  49. rb = GetComponent<Rigidbody>();
  50. }
  51. rb.centerOfMass += shiftCentre;
  52. }
  53. // handle shifting a gear up
  54. public void ShiftUp()
  55. {
  56. float now = Time.timeSinceLevelLoad;
  57. // check if we have waited long enough to shift
  58. if (now < nextShift) return;
  59. // check if we can shift up
  60. if (currentGear < gears.Length - 1)
  61. {
  62. currentGear++;
  63. if (gears[currentGear].sprite != null)
  64. {
  65. gearImage.sprite = gears[currentGear].sprite;
  66. }
  67. // we delay the next shift with 1s. (sorry, hardcoded)
  68. nextShift = now + shiftDelay;
  69. }
  70. }
  71. // handle shifting a gear down
  72. public void ShiftDown()
  73. {
  74. float now = Time.timeSinceLevelLoad;
  75. // check if we have waited long enough to shift
  76. if (now < nextShift) return;
  77. // check if we can shift down (note gear 0 is reverse)
  78. if (currentGear > 0)
  79. {
  80. currentGear--;
  81. if (gears[currentGear].sprite != null)
  82. {
  83. gearImage.sprite = gears[currentGear].sprite;
  84. }
  85. // we delay the next shift with 1/10s. (sorry, hardcoded)
  86. nextShift = now + shiftDelay;
  87. }
  88. }
  89. float wantedRPM = 0.0f; // rpm the engine tries to reach
  90. float motorRPM = 0.0f;
  91. protected virtual void UpdateSpeedoMeter() {
  92. if (speedometer != null)
  93. {
  94. speedometer.setSpeed(rb.velocity.magnitude * 3.6F);
  95. }
  96. }
  97. protected virtual void UpdateRpmMeter()
  98. {
  99. if (rpmMeter != null)
  100. {
  101. rpmMeter.setSpeed(motorRPM);
  102. }
  103. }
  104. protected void move(float steer, float accel, float gear, float brake) {
  105. if (!GameController.Instance.countDownEnded) {
  106. return;
  107. }
  108. // handle automatic shifting
  109. if (automatic && (currentGear == 1) && (accel < 0.0f))
  110. {
  111. ShiftDown(); // reverse
  112. }
  113. else if (automatic && (currentGear == 0) && (accel > 0.0f))
  114. {
  115. ShiftUp(); // go from reverse to first gear
  116. }
  117. else if (automatic && (motorRPM > shiftUpRPM) && (accel > 0.0f))
  118. {
  119. ShiftUp(); // shift up
  120. }
  121. else if (automatic && (motorRPM < shiftDownRPM) && (currentGear > 1))
  122. {
  123. ShiftDown(); // shift down
  124. }
  125. if (automatic && (currentGear == 0))
  126. {
  127. accel = -accel; // in automatic mode we need to hold arrow down for reverse
  128. }
  129. if (accel < 0.0f)
  130. {
  131. // if we try to decelerate we brake.
  132. brake = 1;
  133. accel = 0.0f;
  134. wantedRPM = 0.0f;
  135. }
  136. if (gear > 0)
  137. {
  138. ShiftUp();
  139. }
  140. else if (gear < 0)
  141. {
  142. ShiftDown();
  143. }
  144. // the RPM we try to achieve.
  145. wantedRPM = (maxRPM * accel) * 0.1f + wantedRPM * 0.9f;
  146. float rpm = 0.0f;
  147. int motorizedWheels = 0;
  148. // calc rpm from current wheel speed and do some updating
  149. foreach (Wheel w in wheels)
  150. {
  151. WheelCollider wheel = w.wheel;
  152. // only calculate rpm on wheels that are connected to engine
  153. if (w.motor)
  154. {
  155. rpm += wheel.rpm;
  156. motorizedWheels++;
  157. }
  158. // calculate the local rotation of the wheels from the delta time and rpm
  159. // then set the local rotation accordingly (also adjust for steering)
  160. ApplyLocalPositionToVisuals(wheel);
  161. }
  162. // calculate the actual motor rpm from the wheels connected to the engine
  163. // note we haven't corrected for gear yet.
  164. if (motorizedWheels > 1)
  165. {
  166. rpm = rpm / motorizedWheels;
  167. }
  168. // we do some delay of the change (should take delta instead of just 95% of
  169. // previous rpm, and also adjust or gears.
  170. motorRPM = 0.95f * motorRPM + 0.05f * Mathf.Abs(rpm * gears[currentGear].ratio);
  171. if (motorRPM > maxRPM) motorRPM = maxRPM;
  172. // calculate the 'efficiency' (low or high rpm have lower efficiency then the
  173. // ideal efficiency, say 2000RPM, see table
  174. int index = (int)(motorRPM / efficiencyTableStep);
  175. if (index >= efficiencyTable.Length) index = efficiencyTable.Length - 1;
  176. if (index < 0) index = 0;
  177. // calculate torque using gears and efficiency table
  178. float newTorque = torque * gears[currentGear].ratio * efficiencyTable[index];
  179. // go set torque to the wheels
  180. foreach (Wheel w in wheels)
  181. {
  182. WheelCollider col = w.wheel;
  183. // of course, only the wheels connected to the engine can get engine torque
  184. if (w.motor)
  185. {
  186. // only set torque if wheel goes slower than the expected speed
  187. if (Mathf.Abs(col.rpm) > Mathf.Abs(wantedRPM))
  188. {
  189. // wheel goes too fast, set torque to 0
  190. col.motorTorque = 0;
  191. }
  192. else {
  193. //
  194. float curTorque = col.motorTorque;
  195. col.motorTorque = curTorque * 0.9f + newTorque * 0.1f;
  196. }
  197. }
  198. // check if we have to brake
  199. col.brakeTorque = brake * brakeTorque;
  200. // set steering angle
  201. if (w.steering)
  202. {
  203. float steering = Mathf.Clamp( steer * (steerSpeed / (GetComponent<Rigidbody>().velocity.magnitude * steerSlowing)) * Time.fixedDeltaTime, -1 , 1);
  204. if (steering == 0)
  205. {
  206. if (steerAssist)
  207. {
  208. if (col.steerAngle < -0.01)
  209. {
  210. col.steerAngle += steerSpeed * Time.fixedDeltaTime;
  211. }
  212. else if (col.steerAngle > 0.01)
  213. {
  214. col.steerAngle -= steerSpeed * Time.fixedDeltaTime;
  215. }
  216. else {
  217. col.steerAngle = 0;
  218. }
  219. }
  220. else {
  221. col.steerAngle = 0;
  222. }
  223. }
  224. else
  225. {
  226. if (steerAssist)
  227. {
  228. col.steerAngle = maxSteerAngle * steering;
  229. }
  230. else {
  231. col.steerAngle = maxSteerAngle * steer;
  232. }
  233. }
  234. }
  235. }
  236. }
  237. protected virtual void FixedUpdate()
  238. {
  239. float steer = 0; // steering -1.0 .. 1.0
  240. float accel = 0; // accelerating -1.0 .. 1.0
  241. float gear = 0;
  242. float brake = 0; // braking (true is brake)
  243. if ((checkForActive == null) || checkForActive.activeSelf)
  244. {
  245. // we only look at input when the object we monitor is
  246. // active (or we aren't monitoring an object).
  247. steer = Input.GetAxisRaw("Horizontal");
  248. accel = Input.GetAxisRaw("Gas");
  249. brake = Input.GetAxisRaw("Brake");
  250. gear = Input.GetAxisRaw("Gear");
  251. }
  252. move(steer,accel,gear,brake);
  253. }
  254. public void ApplyLocalPositionToVisuals(WheelCollider collider)
  255. {
  256. if (collider.transform.childCount == 0)
  257. {
  258. return;
  259. }
  260. Transform visualWheel = collider.transform.GetChild(0);
  261. Vector3 position;
  262. Quaternion rotation;
  263. collider.GetWorldPose(out position, out rotation);
  264. visualWheel.transform.position = position;
  265. visualWheel.transform.rotation = rotation;
  266. }
  267. protected float GetMotorRPM() {
  268. return motorRPM;
  269. }
  270. }