1 using System;
2 using UnityEngine;
3
4 namespace UnityStandardAssets.Vehicles.Car
5 {
6 internal enum CarDriveType
7 {
8 FrontWheelDrive,
9 RearWheelDrive,
10 FourWheelDrive
11 }
12
13 internal enum SpeedType
14 {
15 MPH,
16 KPH
17 }
18
19 public class CarController : MonoBehaviour
20 {
21 [SerializeField] private CarDriveType m_CarDriveType = CarDriveType.FourWheelDrive;
22 [SerializeField] private WheelCollider[] m_WheelColliders = new WheelCollider[4];
23 [SerializeField] private GameObject[] m_WheelMeshes = new GameObject[4];
24 [SerializeField] private WheelEffects[] m_WheelEffects = new WheelEffects[4];
25 [SerializeField] private Vector3 m_CentreOfMassOffset;
26 [SerializeField] private float m_MaximumSteerAngle;
27 [Range(0, 1)] [SerializeField] private float m_SteerHelper; // 0 is raw physics , 1 the car will grip in the direction it is facing
28 [Range(0, 1)] [SerializeField] private float m_TractionControl; // 0 is no traction control, 1 is full interference
29 [SerializeField] private float m_FullTorqueOverAllWheels;
30 [SerializeField] private float m_ReverseTorque;
31 [SerializeField] private float m_MaxHandbrakeTorque;
32 [SerializeField] private float m_Downforce = 100f;
33 [SerializeField] private SpeedType m_SpeedType;
34 [SerializeField] private float m_Topspeed = 200;
35 [SerializeField] private static int NoOfGears = 5;
36 [SerializeField] private float m_RevRangeBoundary = 1f;
37 [SerializeField] private float m_SlipLimit;
38 [SerializeField] private float m_BrakeTorque;
39
40 private Quaternion[] m_WheelMeshLocalRotations;
41 private Vector3 m_Prevpos, m_Pos;
42 private float m_SteerAngle;
43 private int m_GearNum;
44 private float m_GearFactor;
45 private float m_OldRotation;
46 private float m_CurrentTorque;
47 private Rigidbody m_Rigidbody;
48 private const float k_ReversingThreshold = 0.01f;
49
50 public bool Skidding { get; private set; }
51 public float BrakeInput { get; private set; }
52 public float CurrentSteerAngle{ get { return m_SteerAngle; }}
53 public float CurrentSpeed{ get { return m_Rigidbody.velocity.magnitude*2.23693629f; }}
54 public float MaxSpeed{get { return m_Topspeed; }}
55 public float Revs { get; private set; }
56 public float AccelInput { get; private set; }
57
58 // Use this for initialization
59 private void Start()
60 {
61 m_WheelMeshLocalRotations = new Quaternion[4];
62 for (int i = 0; i < 4; i++)
63 {
64 m_WheelMeshLocalRotations[i] = m_WheelMeshes[i].transform.localRotation;
65 }
66 m_WheelColliders[0].attachedRigidbody.centerOfMass = m_CentreOfMassOffset;
67
68 m_MaxHandbrakeTorque = float.MaxValue;
69
70 m_Rigidbody = GetComponent<Rigidbody>();
71 m_CurrentTorque = m_FullTorqueOverAllWheels - (m_TractionControl*m_FullTorqueOverAllWheels);
72 }
73
74
75 private void GearChanging()
76 {
77 float f = Mathf.Abs(CurrentSpeed/MaxSpeed);
78 float upgearlimit = (1/(float) NoOfGears)*(m_GearNum + 1);
79 float downgearlimit = (1/(float) NoOfGears)*m_GearNum;
80
81 if (m_GearNum > 0 && f < downgearlimit)
82 {
83 m_GearNum--;
84 }
85
86 if (f > upgearlimit && (m_GearNum < (NoOfGears - 1)))
87 {
88 m_GearNum++;
89 }
90 }
91
92
93 // simple function to add a curved bias towards 1 for a value in the 0-1 range
94 private static float CurveFactor(float factor)
95 {
96 return 1 - (1 - factor)*(1 - factor);
97 }
98
99
100 // unclamped version of Lerp, to allow value to exceed the from-to range
101 private static float ULerp(float from, float to, float value)
102 {
103 return (1.0f - value)*from + value*to;
104 }
105
106
107 private void CalculateGearFactor()
108 {
109 float f = (1/(float) NoOfGears);
110 // gear factor is a normalised representation of the current speed within the current gear's range of speeds.
111 // We smooth towards the 'target' gear factor, so that revs don't instantly snap up or down when changing gear.
112 var targetGearFactor = Mathf.InverseLerp(f*m_GearNum, f*(m_GearNum + 1), Mathf.Abs(CurrentSpeed/MaxSpeed));
113 m_GearFactor = Mathf.Lerp(m_GearFactor, targetGearFactor, Time.deltaTime*5f);
114 }
115
116
117 private void CalculateRevs()
118 {
119 // calculate engine revs (for display / sound)
120 // (this is done in retrospect - revs are not used in force/power calculations)
121 CalculateGearFactor();
122 var gearNumFactor = m_GearNum/(float) NoOfGears;
123 var revsRangeMin = ULerp(0f, m_RevRangeBoundary, CurveFactor(gearNumFactor));
124 var revsRangeMax = ULerp(m_RevRangeBoundary, 1f, gearNumFactor);
125 Revs = ULerp(revsRangeMin, revsRangeMax, m_GearFactor);
126 }
127
128
129 public void Move(float steering, float accel, float footbrake, float handbrake)
130 {
131 for (int i = 0; i < 4; i++)
132 {
133 Quaternion quat;
134 Vector3 position;
135 m_WheelColliders[i].GetWorldPose(out position, out quat);
136 m_WheelMeshes[i].transform.position = position;
137 m_WheelMeshes[i].transform.rotation = quat;
138 }
139
140 //clamp input values
141 steering = Mathf.Clamp(steering, -1, 1);
142 AccelInput = accel = Mathf.Clamp(accel, 0, 1);
143 BrakeInput = footbrake = -1*Mathf.Clamp(footbrake, -1, 0);
144 handbrake = Mathf.Clamp(handbrake, 0, 1);
145
146 //Set the steer on the front wheels.
147 //Assuming that wheels 0 and 1 are the front wheels.
148 m_SteerAngle = steering*m_MaximumSteerAngle;
149 m_WheelColliders[0].steerAngle = m_SteerAngle;
150 m_WheelColliders[1].steerAngle = m_SteerAngle;
151
152 SteerHelper();
153 ApplyDrive(accel, footbrake);
154 CapSpeed();
155
156 //Set the handbrake.
157 //Assuming that wheels 2 and 3 are the rear wheels.
158 if (handbrake > 0f)
159 {
160 var hbTorque = handbrake*m_MaxHandbrakeTorque;
161 m_WheelColliders[2].brakeTorque = hbTorque;
162 m_WheelColliders[3].brakeTorque = hbTorque;
163 }
164
165
166 CalculateRevs();
167 GearChanging();
168
169 AddDownForce();
170 CheckForWheelSpin();
171 TractionControl();
172 }
173
174
175 private void CapSpeed()
176 {
177 float speed = m_Rigidbody.velocity.magnitude;
178 switch (m_SpeedType)
179 {
180 case SpeedType.MPH:
181
182 speed *= 2.23693629f;
183 if (speed > m_Topspeed)
184 m_Rigidbody.velocity = (m_Topspeed/2.23693629f) * m_Rigidbody.velocity.normalized;
185 break;
186
187 case SpeedType.KPH:
188 speed *= 3.6f;
189 if (speed > m_Topspeed)
190 m_Rigidbody.velocity = (m_Topspeed/3.6f) * m_Rigidbody.velocity.normalized;
191 break;
192 }
193 }
194
195
196 private void ApplyDrive(float accel, float footbrake)
197 {
198
199 float thrustTorque;
200 switch (m_CarDriveType)
201 {
202 case CarDriveType.FourWheelDrive:
203 thrustTorque = accel * (m_CurrentTorque / 4f);
204 for (int i = 0; i < 4; i++)
205 {
206 m_WheelColliders[i].motorTorque = thrustTorque;
207 }
208 break;
209
210 case CarDriveType.FrontWheelDrive:
211 thrustTorque = accel * (m_CurrentTorque / 2f);
212 m_WheelColliders[0].motorTorque = m_WheelColliders[1].motorTorque = thrustTorque;
213 break;
214
215 case CarDriveType.RearWheelDrive:
216 thrustTorque = accel * (m_CurrentTorque / 2f);
217 m_WheelColliders[2].motorTorque = m_WheelColliders[3].motorTorque = thrustTorque;
218 break;
219
220 }
221
222 for (int i = 0; i < 4; i++)
223 {
224 if (CurrentSpeed > 5 && Vector3.Angle(transform.forward, m_Rigidbody.velocity) < 50f)
225 {
226 m_WheelColliders[i].brakeTorque = m_BrakeTorque*footbrake;
227 }
228 else if (footbrake > 0)
229 {
230 m_WheelColliders[i].brakeTorque = 0f;
231 m_WheelColliders[i].motorTorque = -m_ReverseTorque*footbrake;
232 }
233 }
234 }
235
236
237 private void SteerHelper()
238 {
239 for (int i = 0; i < 4; i++)
240 {
241 WheelHit wheelhit;
242 m_WheelColliders[i].GetGroundHit(out wheelhit);
243 if (wheelhit.normal == Vector3.zero)
244 return; // wheels arent on the ground so dont realign the rigidbody velocity
245 }
246
247 // this if is needed to avoid gimbal lock problems that will make the car suddenly shift direction
248 if (Mathf.Abs(m_OldRotation - transform.eulerAngles.y) < 10f)
249 {
250 var turnadjust = (transform.eulerAngles.y - m_OldRotation) * m_SteerHelper;
251 Quaternion velRotation = Quaternion.AngleAxis(turnadjust, Vector3.up);
252 m_Rigidbody.velocity = velRotation * m_Rigidbody.velocity;
253 }
254 m_OldRotation = transform.eulerAngles.y;
255 }
256
257
258 // this is used to add more grip in relation to speed
259 private void AddDownForce()
260 {
261 m_WheelColliders[0].attachedRigidbody.AddForce(-transform.up*m_Downforce*
262 m_WheelColliders[0].attachedRigidbody.velocity.magnitude);
263 }
264
265
266 // checks if the wheels are spinning and is so does three things
267 // 1) emits particles
268 // 2) plays tiure skidding sounds
269 // 3) leaves skidmarks on the ground
270 // these effects are controlled through the WheelEffects class
271 private void CheckForWheelSpin()
272 {
273 // loop through all wheels
274 for (int i = 0; i < 4; i++)
275 {
276 WheelHit wheelHit;
277 m_WheelColliders[i].GetGroundHit(out wheelHit);
278
279 // is the tire slipping above the given threshhold
280 if (Mathf.Abs(wheelHit.forwardSlip) >= m_SlipLimit || Mathf.Abs(wheelHit.sidewaysSlip) >= m_SlipLimit)
281 {
282 m_WheelEffects[i].EmitTyreSmoke();
283
284 // avoiding all four tires screeching at the same time
285 // if they do it can lead to some strange audio artefacts
286 if (!AnySkidSoundPlaying())
287 {
288 m_WheelEffects[i].PlayAudio();
289 }
290 continue;
291 }
292
293 // if it wasnt slipping stop all the audio
294 if (m_WheelEffects[i].PlayingAudio)
295 {
296 m_WheelEffects[i].StopAudio();
297 }
298 // end the trail generation
299 m_WheelEffects[i].EndSkidTrail();
300 }
301 }
302
303 // crude traction control that reduces the power to wheel if the car is wheel spinning too much
304 private void TractionControl()
305 {
306 WheelHit wheelHit;
307 switch (m_CarDriveType)
308 {
309 case CarDriveType.FourWheelDrive:
310 // loop through all wheels
311 for (int i = 0; i < 4; i++)
312 {
313 m_WheelColliders[i].GetGroundHit(out wheelHit);
314
315 AdjustTorque(wheelHit.forwardSlip);
316 }
317 break;
318
319 case CarDriveType.RearWheelDrive:
320 m_WheelColliders[2].GetGroundHit(out wheelHit);
321 AdjustTorque(wheelHit.forwardSlip);
322
323 m_WheelColliders[3].GetGroundHit(out wheelHit);
324 AdjustTorque(wheelHit.forwardSlip);
325 break;
326
327 case CarDriveType.FrontWheelDrive:
328 m_WheelColliders[0].GetGroundHit(out wheelHit);
329 AdjustTorque(wheelHit.forwardSlip);
330
331 m_WheelColliders[1].GetGroundHit(out wheelHit);
332 AdjustTorque(wheelHit.forwardSlip);
333 break;
334 }
335 }
336
337
338 private void AdjustTorque(float forwardSlip)
339 {
340 if (forwardSlip >= m_SlipLimit && m_CurrentTorque >= 0)
341 {
342 m_CurrentTorque -= 10 * m_TractionControl;
343 }
344 else
345 {
346 m_CurrentTorque += 10 * m_TractionControl;
347 if (m_CurrentTorque > m_FullTorqueOverAllWheels)
348 {
349 m_CurrentTorque = m_FullTorqueOverAllWheels;
350 }
351 }
352 }
353
354
355 private bool AnySkidSoundPlaying()
356 {
357 for (int i = 0; i < 4; i++)
358 {
359 if (m_WheelEffects[i].PlayingAudio)
360 {
361 return true;
362 }
363 }
364 return false;
365 }
366 }
367 }
2 using UnityEngine;
3
4 namespace UnityStandardAssets.Vehicles.Car
5 {
6 internal enum CarDriveType
7 {
8 FrontWheelDrive,
9 RearWheelDrive,
10 FourWheelDrive
11 }
12
13 internal enum SpeedType
14 {
15 MPH,
16 KPH
17 }
18
19 public class CarController : MonoBehaviour
20 {
21 [SerializeField] private CarDriveType m_CarDriveType = CarDriveType.FourWheelDrive;
22 [SerializeField] private WheelCollider[] m_WheelColliders = new WheelCollider[4];
23 [SerializeField] private GameObject[] m_WheelMeshes = new GameObject[4];
24 [SerializeField] private WheelEffects[] m_WheelEffects = new WheelEffects[4];
25 [SerializeField] private Vector3 m_CentreOfMassOffset;
26 [SerializeField] private float m_MaximumSteerAngle;
27 [Range(0, 1)] [SerializeField] private float m_SteerHelper; // 0 is raw physics , 1 the car will grip in the direction it is facing
28 [Range(0, 1)] [SerializeField] private float m_TractionControl; // 0 is no traction control, 1 is full interference
29 [SerializeField] private float m_FullTorqueOverAllWheels;
30 [SerializeField] private float m_ReverseTorque;
31 [SerializeField] private float m_MaxHandbrakeTorque;
32 [SerializeField] private float m_Downforce = 100f;
33 [SerializeField] private SpeedType m_SpeedType;
34 [SerializeField] private float m_Topspeed = 200;
35 [SerializeField] private static int NoOfGears = 5;
36 [SerializeField] private float m_RevRangeBoundary = 1f;
37 [SerializeField] private float m_SlipLimit;
38 [SerializeField] private float m_BrakeTorque;
39
40 private Quaternion[] m_WheelMeshLocalRotations;
41 private Vector3 m_Prevpos, m_Pos;
42 private float m_SteerAngle;
43 private int m_GearNum;
44 private float m_GearFactor;
45 private float m_OldRotation;
46 private float m_CurrentTorque;
47 private Rigidbody m_Rigidbody;
48 private const float k_ReversingThreshold = 0.01f;
49
50 public bool Skidding { get; private set; }
51 public float BrakeInput { get; private set; }
52 public float CurrentSteerAngle{ get { return m_SteerAngle; }}
53 public float CurrentSpeed{ get { return m_Rigidbody.velocity.magnitude*2.23693629f; }}
54 public float MaxSpeed{get { return m_Topspeed; }}
55 public float Revs { get; private set; }
56 public float AccelInput { get; private set; }
57
58 // Use this for initialization
59 private void Start()
60 {
61 m_WheelMeshLocalRotations = new Quaternion[4];
62 for (int i = 0; i < 4; i++)
63 {
64 m_WheelMeshLocalRotations[i] = m_WheelMeshes[i].transform.localRotation;
65 }
66 m_WheelColliders[0].attachedRigidbody.centerOfMass = m_CentreOfMassOffset;
67
68 m_MaxHandbrakeTorque = float.MaxValue;
69
70 m_Rigidbody = GetComponent<Rigidbody>();
71 m_CurrentTorque = m_FullTorqueOverAllWheels - (m_TractionControl*m_FullTorqueOverAllWheels);
72 }
73
74
75 private void GearChanging()
76 {
77 float f = Mathf.Abs(CurrentSpeed/MaxSpeed);
78 float upgearlimit = (1/(float) NoOfGears)*(m_GearNum + 1);
79 float downgearlimit = (1/(float) NoOfGears)*m_GearNum;
80
81 if (m_GearNum > 0 && f < downgearlimit)
82 {
83 m_GearNum--;
84 }
85
86 if (f > upgearlimit && (m_GearNum < (NoOfGears - 1)))
87 {
88 m_GearNum++;
89 }
90 }
91
92
93 // simple function to add a curved bias towards 1 for a value in the 0-1 range
94 private static float CurveFactor(float factor)
95 {
96 return 1 - (1 - factor)*(1 - factor);
97 }
98
99
100 // unclamped version of Lerp, to allow value to exceed the from-to range
101 private static float ULerp(float from, float to, float value)
102 {
103 return (1.0f - value)*from + value*to;
104 }
105
106
107 private void CalculateGearFactor()
108 {
109 float f = (1/(float) NoOfGears);
110 // gear factor is a normalised representation of the current speed within the current gear's range of speeds.
111 // We smooth towards the 'target' gear factor, so that revs don't instantly snap up or down when changing gear.
112 var targetGearFactor = Mathf.InverseLerp(f*m_GearNum, f*(m_GearNum + 1), Mathf.Abs(CurrentSpeed/MaxSpeed));
113 m_GearFactor = Mathf.Lerp(m_GearFactor, targetGearFactor, Time.deltaTime*5f);
114 }
115
116
117 private void CalculateRevs()
118 {
119 // calculate engine revs (for display / sound)
120 // (this is done in retrospect - revs are not used in force/power calculations)
121 CalculateGearFactor();
122 var gearNumFactor = m_GearNum/(float) NoOfGears;
123 var revsRangeMin = ULerp(0f, m_RevRangeBoundary, CurveFactor(gearNumFactor));
124 var revsRangeMax = ULerp(m_RevRangeBoundary, 1f, gearNumFactor);
125 Revs = ULerp(revsRangeMin, revsRangeMax, m_GearFactor);
126 }
127
128
129 public void Move(float steering, float accel, float footbrake, float handbrake)
130 {
131 for (int i = 0; i < 4; i++)
132 {
133 Quaternion quat;
134 Vector3 position;
135 m_WheelColliders[i].GetWorldPose(out position, out quat);
136 m_WheelMeshes[i].transform.position = position;
137 m_WheelMeshes[i].transform.rotation = quat;
138 }
139
140 //clamp input values
141 steering = Mathf.Clamp(steering, -1, 1);
142 AccelInput = accel = Mathf.Clamp(accel, 0, 1);
143 BrakeInput = footbrake = -1*Mathf.Clamp(footbrake, -1, 0);
144 handbrake = Mathf.Clamp(handbrake, 0, 1);
145
146 //Set the steer on the front wheels.
147 //Assuming that wheels 0 and 1 are the front wheels.
148 m_SteerAngle = steering*m_MaximumSteerAngle;
149 m_WheelColliders[0].steerAngle = m_SteerAngle;
150 m_WheelColliders[1].steerAngle = m_SteerAngle;
151
152 SteerHelper();
153 ApplyDrive(accel, footbrake);
154 CapSpeed();
155
156 //Set the handbrake.
157 //Assuming that wheels 2 and 3 are the rear wheels.
158 if (handbrake > 0f)
159 {
160 var hbTorque = handbrake*m_MaxHandbrakeTorque;
161 m_WheelColliders[2].brakeTorque = hbTorque;
162 m_WheelColliders[3].brakeTorque = hbTorque;
163 }
164
165
166 CalculateRevs();
167 GearChanging();
168
169 AddDownForce();
170 CheckForWheelSpin();
171 TractionControl();
172 }
173
174
175 private void CapSpeed()
176 {
177 float speed = m_Rigidbody.velocity.magnitude;
178 switch (m_SpeedType)
179 {
180 case SpeedType.MPH:
181
182 speed *= 2.23693629f;
183 if (speed > m_Topspeed)
184 m_Rigidbody.velocity = (m_Topspeed/2.23693629f) * m_Rigidbody.velocity.normalized;
185 break;
186
187 case SpeedType.KPH:
188 speed *= 3.6f;
189 if (speed > m_Topspeed)
190 m_Rigidbody.velocity = (m_Topspeed/3.6f) * m_Rigidbody.velocity.normalized;
191 break;
192 }
193 }
194
195
196 private void ApplyDrive(float accel, float footbrake)
197 {
198
199 float thrustTorque;
200 switch (m_CarDriveType)
201 {
202 case CarDriveType.FourWheelDrive:
203 thrustTorque = accel * (m_CurrentTorque / 4f);
204 for (int i = 0; i < 4; i++)
205 {
206 m_WheelColliders[i].motorTorque = thrustTorque;
207 }
208 break;
209
210 case CarDriveType.FrontWheelDrive:
211 thrustTorque = accel * (m_CurrentTorque / 2f);
212 m_WheelColliders[0].motorTorque = m_WheelColliders[1].motorTorque = thrustTorque;
213 break;
214
215 case CarDriveType.RearWheelDrive:
216 thrustTorque = accel * (m_CurrentTorque / 2f);
217 m_WheelColliders[2].motorTorque = m_WheelColliders[3].motorTorque = thrustTorque;
218 break;
219
220 }
221
222 for (int i = 0; i < 4; i++)
223 {
224 if (CurrentSpeed > 5 && Vector3.Angle(transform.forward, m_Rigidbody.velocity) < 50f)
225 {
226 m_WheelColliders[i].brakeTorque = m_BrakeTorque*footbrake;
227 }
228 else if (footbrake > 0)
229 {
230 m_WheelColliders[i].brakeTorque = 0f;
231 m_WheelColliders[i].motorTorque = -m_ReverseTorque*footbrake;
232 }
233 }
234 }
235
236
237 private void SteerHelper()
238 {
239 for (int i = 0; i < 4; i++)
240 {
241 WheelHit wheelhit;
242 m_WheelColliders[i].GetGroundHit(out wheelhit);
243 if (wheelhit.normal == Vector3.zero)
244 return; // wheels arent on the ground so dont realign the rigidbody velocity
245 }
246
247 // this if is needed to avoid gimbal lock problems that will make the car suddenly shift direction
248 if (Mathf.Abs(m_OldRotation - transform.eulerAngles.y) < 10f)
249 {
250 var turnadjust = (transform.eulerAngles.y - m_OldRotation) * m_SteerHelper;
251 Quaternion velRotation = Quaternion.AngleAxis(turnadjust, Vector3.up);
252 m_Rigidbody.velocity = velRotation * m_Rigidbody.velocity;
253 }
254 m_OldRotation = transform.eulerAngles.y;
255 }
256
257
258 // this is used to add more grip in relation to speed
259 private void AddDownForce()
260 {
261 m_WheelColliders[0].attachedRigidbody.AddForce(-transform.up*m_Downforce*
262 m_WheelColliders[0].attachedRigidbody.velocity.magnitude);
263 }
264
265
266 // checks if the wheels are spinning and is so does three things
267 // 1) emits particles
268 // 2) plays tiure skidding sounds
269 // 3) leaves skidmarks on the ground
270 // these effects are controlled through the WheelEffects class
271 private void CheckForWheelSpin()
272 {
273 // loop through all wheels
274 for (int i = 0; i < 4; i++)
275 {
276 WheelHit wheelHit;
277 m_WheelColliders[i].GetGroundHit(out wheelHit);
278
279 // is the tire slipping above the given threshhold
280 if (Mathf.Abs(wheelHit.forwardSlip) >= m_SlipLimit || Mathf.Abs(wheelHit.sidewaysSlip) >= m_SlipLimit)
281 {
282 m_WheelEffects[i].EmitTyreSmoke();
283
284 // avoiding all four tires screeching at the same time
285 // if they do it can lead to some strange audio artefacts
286 if (!AnySkidSoundPlaying())
287 {
288 m_WheelEffects[i].PlayAudio();
289 }
290 continue;
291 }
292
293 // if it wasnt slipping stop all the audio
294 if (m_WheelEffects[i].PlayingAudio)
295 {
296 m_WheelEffects[i].StopAudio();
297 }
298 // end the trail generation
299 m_WheelEffects[i].EndSkidTrail();
300 }
301 }
302
303 // crude traction control that reduces the power to wheel if the car is wheel spinning too much
304 private void TractionControl()
305 {
306 WheelHit wheelHit;
307 switch (m_CarDriveType)
308 {
309 case CarDriveType.FourWheelDrive:
310 // loop through all wheels
311 for (int i = 0; i < 4; i++)
312 {
313 m_WheelColliders[i].GetGroundHit(out wheelHit);
314
315 AdjustTorque(wheelHit.forwardSlip);
316 }
317 break;
318
319 case CarDriveType.RearWheelDrive:
320 m_WheelColliders[2].GetGroundHit(out wheelHit);
321 AdjustTorque(wheelHit.forwardSlip);
322
323 m_WheelColliders[3].GetGroundHit(out wheelHit);
324 AdjustTorque(wheelHit.forwardSlip);
325 break;
326
327 case CarDriveType.FrontWheelDrive:
328 m_WheelColliders[0].GetGroundHit(out wheelHit);
329 AdjustTorque(wheelHit.forwardSlip);
330
331 m_WheelColliders[1].GetGroundHit(out wheelHit);
332 AdjustTorque(wheelHit.forwardSlip);
333 break;
334 }
335 }
336
337
338 private void AdjustTorque(float forwardSlip)
339 {
340 if (forwardSlip >= m_SlipLimit && m_CurrentTorque >= 0)
341 {
342 m_CurrentTorque -= 10 * m_TractionControl;
343 }
344 else
345 {
346 m_CurrentTorque += 10 * m_TractionControl;
347 if (m_CurrentTorque > m_FullTorqueOverAllWheels)
348 {
349 m_CurrentTorque = m_FullTorqueOverAllWheels;
350 }
351 }
352 }
353
354
355 private bool AnySkidSoundPlaying()
356 {
357 for (int i = 0; i < 4; i++)
358 {
359 if (m_WheelEffects[i].PlayingAudio)
360 {
361 return true;
362 }
363 }
364 return false;
365 }
366 }
367 }