Wheel Collider
Wheel Collider
cs 1
1 //----------------------------------------------
2 // Realistic Car Controller
3 //
4 // Copyright © 2014 - 2023 BoneCracker Games
5 // https://www.bonecrackergames.com
6 // Buğra Özdoğanlar
7 //
8 //----------------------------------------------
9
10
11 using UnityEngine;
12 using System.Linq;
13 using System.Collections;
14 using System.Collections.Generic;
15
16 /// <summary>
17 /// Based on Unity's WheelCollider. Modifies forward and sideways
curves, settings in order to get stable and realistic physics
depends on selected behavior in RCC Settings.
18 /// </summary>
19 [RequireComponent(typeof(WheelCollider))]
20 [AddComponentMenu("BoneCracker Games/Realistic Car Controller/Main/RCC
Wheel Collider")]
21 public class RCC_WheelCollider : RCC_Core {
22
23 #region OBSOLETE VARIABLES
24
25 [System.Obsolete("Use CarController instead of carController")]
26 public RCC_CarControllerV3 carController {
27
28 get {
29
30 return CarController;
31
32 }
33
34 }
35
36 [System.Obsolete("Use WheelCollider instead of wheelCollider")]
37 public WheelCollider wheelCollider {
38
39 get {
40
41 return WheelCollider;
42
43 }
44
45 }
46
47 [System.Obsolete("Use Rigid instead of rigid")]
48 public Rigidbody rigid {
49
50 get {
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 2
51
52 return Rigid;
53
54 }
55
56 }
57
58 #endregion
59
60 // Car controller.
61 public RCC_CarControllerV3 CarController {
62 get {
63 if (_carController == null)
64 _carController =
GetComponentInParent<RCC_CarControllerV3>();
65 return _carController;
66 }
67 }
68 private RCC_CarControllerV3 _carController;
69
70 // WheelCollider.
71 public WheelCollider WheelCollider {
72 get {
73 if (_wheelCollider == null)
74 _wheelCollider = GetComponent<WheelCollider>();
75 return _wheelCollider;
76 }
77 }
78 private WheelCollider _wheelCollider;
79
80 // Rigidbody of the vehicle.
81 private Rigidbody Rigid {
82 get {
83 if (_rigid == null)
84 _rigid = CarController.Rigid;
85 return _rigid;
86 }
87 }
88 private Rigidbody _rigid;
89
90 public Transform wheelModel; // Wheel model for animating
and aligning.
91
92 public WheelHit wheelHit; // Wheelhit data.
93 public bool isGrounded = false; // Is wheel grounded or not?
94 public int groundIndex = 0; // Current ground index of
wheelhit.
95
96 public bool alignWheel = true; // Align the wheelmodel with
wheelcollider position and rotation.
97 public bool drawSkid = true; // Draw skidmarks.
98
99 // Locating correct position and rotation for the wheel.
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 3
100 [HideInInspector] public Vector3 wheelPosition = Vector3.zero;
101 [HideInInspector] public Quaternion wheelRotation =
Quaternion.identity;
102
103 [Space()]
104 public bool canPower = false; // Can this wheel apply
power?
105 [Range(-1f, 1f)] public float powerMultiplier = 1f;
106 public bool canSteer = false; // Can this wheel apply
steer?
107 [Range(-1f, 1f)] public float steeringMultiplier = 1f;
108 public bool canBrake = false; // Can this wheel apply
brake?
109 [Range(0f, 1f)] public float brakingMultiplier = 1f;
110 public bool canHandbrake = false; // Can this wheel apply
handbrake?
111 [Range(0f, 1f)] public float handbrakeMultiplier = 1f;
112
113 [Space()]
114 public float wheelWidth = .275f; // Width of the wheel.
115 public float wheelOffset = 0f; // Offset by X axis.
116
117 private float wheelRPM2Speed = 0f; // Wheel RPM to Speed in
km/h unit.
118
119 [Space()]
120 [Range(-5f, 5f)] public float camber = 0f; // Camber angle.
121 [Range(-5f, 5f)] public float caster = 0f; // Caster angle.
122 [Range(-5f, 5f)] public float toe = 0f; // Toe angle.
123 [Space()]
124
125 // Skidmarks
126 private int lastSkidmark = -1;
127
128 // Slips
129 [HideInInspector] public float wheelSlipAmountForward =
0f; // Forward slip.
130 [HideInInspector] public float wheelSlipAmountSideways = 0f; //
Sideways slip.
131 [HideInInspector] public float totalSlip =
0f; // Total amount of forward and
sideways slips.
132
133 // WheelFriction Curves and Stiffness.
134 private WheelFrictionCurve forwardFrictionCurve; //
Forward friction curve.
135 private WheelFrictionCurve sidewaysFrictionCurve; // Sideways
friction curve.
136
137 // Original WheelFriction Curves and Stiffness.
138 private WheelFrictionCurve forwardFrictionCurve_Org; //
Forward friction curve original.
139 private WheelFrictionCurve sidewaysFrictionCurve_Org; //
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 4
Sideways friction curve original.
140
141 // Audio
142 private AudioSource audioSource; // Audiosource for tire
skid SFX.
143 private AudioClip audioClip; // Audioclip for
tire skid SFX.
144 private float audioVolume = 1f; // Maximum volume for
tire skid SFX.
145
146 // List for all particle systems.
147 [HideInInspector] public List<ParticleSystem> allWheelParticles =
new List<ParticleSystem>();
148 private ParticleSystem.EmissionModule emission;
149
150 // Tractions used for smooth drifting.
151 [HideInInspector] public float tractionHelpedSidewaysStiffness =
1f;
152 private readonly float minForwardStiffness = .9f;
153 private readonly float maxForwardStiffness = 1f;
154 private readonly float minSidewaysStiffness = .5f;
155 private readonly float maxSidewaysStiffness = 1f;
156
157 // Getting bump force.
158 [HideInInspector] public float bumpForce, oldForce, RotationValue
= 0f;
159
160 private bool deflated = false; // Deflated or not?
161
162 [Space()]
163 public float deflateRadiusMultiplier = .8f; // Deflated
radius multiplier. Radius of the wheelcollider will be multiplied
by this value on deflate.
164 public float deflatedStiffnessMultiplier = .5f; // Deflated
stiffness of the wheelcollider.
165 private float defRadius = -1f; // Original radius of the
wheelcollider.
166
167 // Getting audioclips from the RCC Settings.
168 public AudioClip DeflateAudio {
169
170 get {
171
172 return RCC_Settings.Instance.wheelDeflateClip;
173
174 }
175
176 }
177 public AudioClip InflateAudio {
178
179 get {
180
181 return RCC_Settings.Instance.wheelInflateClip;
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 5
182
183 }
184
185 }
186
187 private AudioSource flatSource;
188 public AudioClip FlatAudio {
189
190 get {
191
192 return RCC_Settings.Instance.wheelFlatClip;
193
194 }
195
196 }
197
198 private ParticleSystem _wheelDeflateParticles;
199 public ParticleSystem WheelDeflateParticles {
200
201 get {
202
203 return
RCC_Settings.Instance.wheelDeflateParticles.GetComponent<
ParticleSystem>();
204
205 }
206
207 }
208
209 private void Start() {
210
211 // Increasing wheelcollider mass for avoiding unstable
behavior.
212 if (RCC_Settings.Instance.useFixedWheelColliders)
213 WheelCollider.mass = Rigid.mass / 15f;
214
215 CreatePivotOfTheWheel();
216 UpdateWheelFrictions();
217 OverrideWheelSettings();
218 CreateAudio();
219 CreateParticles();
220
221 }
222
223 /// <summary>
224 /// Creating pivot point of the wheel.
225 /// </summary>
226 private void CreatePivotOfTheWheel() {
227
228 // Creating pivot position of the wheel at correct position
and rotation.
229 GameObject newPivot = new GameObject("Pivot_" +
wheelModel.transform.name);
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 6
230 newPivot.transform.position = RCC_GetBounds.GetBoundsCenter
(wheelModel.transform);
231 newPivot.transform.rotation = transform.rotation;
232 newPivot.transform.SetParent(wheelModel.transform.parent,
true);
233
234 // Assigning temporary created wheel to actual wheel.
235 wheelModel.SetParent(newPivot.transform, true);
236 wheelModel = newPivot.transform;
237
238 }
239
240 /// <summary>
241 /// Creating pacticles.
242 /// </summary>
243 private void CreateParticles() {
244
245 if (RCC_Settings.Instance.dontUseAnyParticleEffects)
246 return;
247
248 for (int i = 0; i <
RCC_GroundMaterials.Instance.frictions.Length; i++) {
249
250 GameObject ps = Instantiate
(RCC_GroundMaterials.Instance.frictions
[i].groundParticles, transform.position,
transform.rotation);
251 emission = ps.GetComponent<ParticleSystem>().emission;
252 emission.enabled = false;
253 ps.transform.SetParent(transform, false);
254 ps.transform.localPosition = Vector3.zero;
255 ps.transform.localRotation = Quaternion.identity;
256 allWheelParticles.Add(ps.GetComponent<ParticleSystem>());
257
258 }
259
260 }
261
262 /// <summary>
263 /// Creating audiosource.
264 /// </summary>
265 private void CreateAudio() {
266
267 // Creating audiosource for skid SFX.
268 audioSource = NewAudioSource(RCC_Settings.Instance.audioMixer,
CarController.gameObject, "Skid Sound AudioSource", 5f,
50f, 0f, audioClip, true, true, false);
269 audioSource.transform.position = transform.position;
270
271 }
272
273 /// <summary>
274 /// Overriding wheel settings.
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 7
275 /// </summary>
276 private void OverrideWheelSettings() {
277
278 // Override wheels automatically if enabled.
279 if (!CarController.overrideAllWheels) {
280
281 // Overriding canPower, canSteer, canBrake, canHandbrake.
282 if (this == CarController.FrontLeftWheelCollider || this
== CarController.FrontRightWheelCollider) {
283
284 canSteer = true;
285 canBrake = true;
286 brakingMultiplier = 1f;
287
288 }
289
290 // Overriding canPower, canSteer, canBrake, canHandbrake.
291 if (this == CarController.RearLeftWheelCollider || this ==
CarController.RearRightWheelCollider) {
292
293 canHandbrake = true;
294 canBrake = true;
295 brakingMultiplier = .75f;
296
297 }
298
299 }
300
301 }
302
303 private void OnEnable() {
304
305 // Listening an event when main behavior changed.
306 RCC_SceneManager.OnBehaviorChanged += UpdateWheelFrictions;
307
308 // If wheel model is assigned but not enabled, enable it.
309 if (wheelModel && !wheelModel.gameObject.activeSelf)
310 wheelModel.gameObject.SetActive(true);
311
312 // Resetting values on enable.
313 wheelSlipAmountForward = 0f;
314 wheelSlipAmountSideways = 0f;
315 totalSlip = 0f;
316 bumpForce = 0f;
317 oldForce = 0f;
318
319 if (audioSource) {
320
321 audioSource.volume = 0f;
322 audioSource.Stop();
323
324 }
325
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 8
326 WheelCollider.motorTorque = 0f;
327 WheelCollider.brakeTorque = 0f;
328 WheelCollider.steerAngle = 0f;
329
330 }
331
332 /// <summary>
333 /// Checks the selected behavior in RCC Settings and applies
changes.
334 /// </summary>
335 private void UpdateWheelFrictions() {
336
337 // Getting forward and sideways frictions of the
wheelcollider.
338 forwardFrictionCurve = WheelCollider.forwardFriction;
339 sidewaysFrictionCurve = WheelCollider.sidewaysFriction;
340
341 // Getting behavior if selected.
342 RCC_Settings.BehaviorType behavior =
RCC_Settings.Instance.selectedBehaviorType;
343
344 // If there is a selected behavior, override friction curves.
345 if (!CarController.overrideBehavior && behavior != null) {
346
347 forwardFrictionCurve = SetFrictionCurves
(forwardFrictionCurve, behavior.forwardExtremumSlip,
behavior.forwardExtremumValue,
behavior.forwardAsymptoteSlip,
behavior.forwardAsymptoteValue);
348 sidewaysFrictionCurve = SetFrictionCurves
(sidewaysFrictionCurve, behavior.sidewaysExtremumSlip,
behavior.sidewaysExtremumValue,
behavior.sidewaysAsymptoteSlip,
behavior.sidewaysAsymptoteValue);
349
350 }
351
352 // Assigning new frictons.
353 WheelCollider.forwardFriction = forwardFrictionCurve;
354 WheelCollider.sidewaysFriction = sidewaysFrictionCurve;
355
356 // Override original frictions.
357 forwardFrictionCurve_Org = WheelCollider.forwardFriction;
358 sidewaysFrictionCurve_Org = WheelCollider.sidewaysFriction;
359
360 }
361
362 private void Update() {
363
364 // Return if RCC is disabled.
365 if (!CarController.enabled)
366 return;
367
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 9
368 // Setting position and rotation of the wheel model.
369 if (alignWheel)
370 WheelAlign();
371
372 }
373
374 private void FixedUpdate() {
375
376 // Return if RCC is disabled.
377 if (!CarController.enabled)
378 return;
379
380 float circumFerence = 2.0f * 3.14f * WheelCollider.radius; //
Finding circumFerence 2 Pi R.
381 wheelRPM2Speed = (circumFerence * WheelCollider.rpm) * 60f; //
Finding MPH and converting to KMH.
382 wheelRPM2Speed = Mathf.Clamp(wheelRPM2Speed / 1000f, 0f,
Mathf.Infinity);
383
384 // Setting power state of the wheels depending on drivetrain
mode. Only overrides them if overrideWheels is enabled for
the vehicle.
385 if (!CarController.overrideAllWheels) {
386
387 switch (CarController.wheelTypeChoise) {
388
389 case RCC_CarControllerV3.WheelType.AWD:
390 canPower = true;
391 break;
392
393 case RCC_CarControllerV3.WheelType.BIASED:
394 canPower = true;
395 break;
396
397 case RCC_CarControllerV3.WheelType.FWD:
398
399 if (this == CarController.FrontLeftWheelCollider
|| this == CarController.FrontRightWheelCollider)
400 canPower = true;
401 else
402 canPower = false;
403
404 break;
405
406 case RCC_CarControllerV3.WheelType.RWD:
407
408 if (this == CarController.RearLeftWheelCollider ||
this == CarController.RearRightWheelCollider)
409 canPower = true;
410 else
411 canPower = false;
412
413 break;
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 10
414
415 }
416
417 }
418
419 GroundMaterial();
420 Frictions();
421 TotalSlip();
422 SkidMarks();
423 Particles();
424 Audio();
425 CheckDeflate();
426 ESP();
427
428 }
429
430 /// <summary>
431 /// ESP System. All wheels have individual brakes. In case of
loosing control of the vehicle, corresponding wheel will brake
for gaining the control again.
432 /// </summary>
433 private void ESP() {
434
435 if (CarController.ESP && CarController.brakeInput < .5f) {
436
437 if (CarController.handbrakeInput < .5f) {
438
439 if (CarController.underSteering) {
440
441 if (this == CarController.FrontLeftWheelCollider)
442 ApplyBrakeTorque((CarController.brakeTorque *
CarController.ESPStrength) * Mathf.Clamp(-
CarController.rearSlip, 0f, Mathf.Infinity));
443
444 if (this == CarController.FrontRightWheelCollider)
445 ApplyBrakeTorque((CarController.brakeTorque *
CarController.ESPStrength) * Mathf.Clamp
(CarController.rearSlip, 0f, Mathf.Infinity));
446
447 }
448
449 if (CarController.overSteering) {
450
451 if (this == CarController.RearLeftWheelCollider)
452 ApplyBrakeTorque((CarController.brakeTorque *
CarController.ESPStrength) * Mathf.Clamp(-
CarController.frontSlip, 0f, Mathf.Infinity));
453
454 if (this == CarController.RearRightWheelCollider)
455 ApplyBrakeTorque((CarController.brakeTorque *
CarController.ESPStrength) * Mathf.Clamp
(CarController.frontSlip, 0f, Mathf.Infinity));
456
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 11
457 }
458
459 }
460
461 }
462
463 }
464
465 /// <summary>
466 /// Aligning wheel model position and rotation.
467 /// </summary>
468 private void WheelAlign() {
469
470 // Return if no wheel model selected.
471 if (!wheelModel) {
472
473 Debug.LogWarning(transform.name + " wheel of the " +
CarController.transform.name + " is missing wheel
model.");
474 return;
475
476 }
477
478 // Getting position and rotation of the wheelcollider and
assigning wheelPosition and wheelRotation.
479 WheelCollider.GetWorldPose(out wheelPosition, out
wheelRotation);
480
481 //Increase the rotation value.
482 RotationValue += WheelCollider.rpm * (360f / 60f) *
Time.deltaTime;
483
484 // Assigning position and rotation to the wheel model.
485 wheelModel.SetPositionAndRotation(wheelPosition,
transform.rotation * Quaternion.Euler(RotationValue,
WheelCollider.steerAngle, 0f));
486
487 // Adjusting camber angle by Z axis.
488 if (transform.localPosition.x < 0f)
489 wheelModel.transform.RotateAround
(wheelModel.transform.position, transform.forward, -
camber);
490 else
491 wheelModel.transform.RotateAround
(wheelModel.transform.position, transform.forward,
camber);
492
493 // Adjusting caster angle by X axis.
494 if (transform.localPosition.x < 0f)
495 wheelModel.transform.RotateAround
(wheelModel.transform.position, transform.right, -
caster);
496 else
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 12
497 wheelModel.transform.RotateAround
(wheelModel.transform.position, transform.right, caster);
498
499 }
500
501 /// <summary>
502 /// Drawing skidmarks if wheel is skidding.
503 /// </summary>
504 private void SkidMarks() {
505
506 // Return if not drawing skidmarks.
507 if (!drawSkid)
508 return;
509
510 // If scene has skidmarks manager...
511 if (!RCC_Settings.Instance.dontUseSkidmarks) {
512
513 // If slips are bigger than target value, draw the
skidmarks.
514 if (totalSlip > RCC_GroundMaterials.Instance.frictions
[groundIndex].slip) {
515
516 Vector3 skidPoint = wheelHit.point + 1f *
Time.deltaTime * (Rigid.velocity);
517
518 if (Rigid.velocity.magnitude > 1f && isGrounded &&
wheelHit.normal != Vector3.zero && wheelHit.point !=
Vector3.zero && skidPoint != Vector3.zero &&
Mathf.Abs(skidPoint.x) > 1f && Mathf.Abs(skidPoint.z)
> 1f)
519 lastSkidmark =
RCC_SkidmarksManager.Instance.AddSkidMark(skidPoint,
wheelHit.normal, totalSlip, wheelWidth, lastSkidmark,
groundIndex);
520 else
521 lastSkidmark = -1;
522
523 } else {
524
525 lastSkidmark = -1;
526
527 }
528
529 }
530
531 }
532
533 /// <summary>
534 /// Sets forward and sideways frictions.
535 /// </summary>
536 private void Frictions() {
537
538 // Handbrake input clamped 0f - 1f.
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 13
539 float hbInput = CarController.handbrakeInput;
540
541 if (canHandbrake && hbInput > .75f)
542 hbInput = .75f;
543 else
544 hbInput = 1f;
545
546 // Setting wheel stiffness to ground physic material
stiffness.
547 forwardFrictionCurve.stiffness =
RCC_GroundMaterials.Instance.frictions
[groundIndex].forwardStiffness;
548 sidewaysFrictionCurve.stiffness =
(RCC_GroundMaterials.Instance.frictions
[groundIndex].sidewaysStiffness * hbInput *
tractionHelpedSidewaysStiffness);
549
550 // If deflated, apply deflated stiffness.
551 if (deflated) {
552
553 forwardFrictionCurve.stiffness *=
deflatedStiffnessMultiplier;
554 sidewaysFrictionCurve.stiffness *=
deflatedStiffnessMultiplier;
555
556 }
557
558 // If drift mode is selected, apply specific frictions.
559 if (!CarController.overrideBehavior &&
RCC_Settings.Instance.selectedBehaviorType != null &&
RCC_Settings.Instance.selectedBehaviorType.applyExternalWhee
lFrictions)
560 Drift();
561
562 // Setting new friction curves to wheels.
563 WheelCollider.forwardFriction = forwardFrictionCurve;
564 WheelCollider.sidewaysFriction = sidewaysFrictionCurve;
565
566 // Also damp too.
567 WheelCollider.wheelDampingRate =
RCC_GroundMaterials.Instance.frictions[groundIndex].damp;
568
569 }
570
571 /// <summary>
572 /// Total amount of wheel slip.
573 /// </summary>
574 private void TotalSlip() {
575
576 // Forward, sideways, and total slips.
577 if (isGrounded && wheelHit.point != Vector3.zero) {
578
579 wheelSlipAmountForward = wheelHit.forwardSlip;
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 14
580 wheelSlipAmountSideways = wheelHit.sidewaysSlip;
581
582 } else {
583
584 wheelSlipAmountForward = 0f;
585 wheelSlipAmountSideways = 0f;
586
587 }
588
589 totalSlip = Mathf.Lerp(totalSlip, ((Mathf.Abs
(wheelSlipAmountSideways) + Mathf.Abs
(wheelSlipAmountForward)) / 2f), Time.fixedDeltaTime * 10f);
590
591 }
592
593 /// <summary>
594 /// Particles.
595 /// </summary>
596 private void Particles() {
597
598 if (RCC_Settings.Instance.dontUseAnyParticleEffects)
599 return;
600
601 // If wheel slip is bigger than ground physic material slip,
enable particles. Otherwise, disable particles.
602 for (int i = 0; i < allWheelParticles.Count; i++) {
603
604 if (totalSlip > RCC_GroundMaterials.Instance.frictions
[groundIndex].slip) {
605
606 if (i != groundIndex) {
607
608 ParticleSystem.EmissionModule em;
609
610 em = allWheelParticles[i].emission;
611 em.enabled = false;
612
613 } else {
614
615 ParticleSystem.EmissionModule em;
616
617 em = allWheelParticles[i].emission;
618 em.enabled = true;
619
620 }
621
622 } else {
623
624 ParticleSystem.EmissionModule em;
625
626 em = allWheelParticles[i].emission;
627 em.enabled = false;
628
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 15
629 }
630
631 if (isGrounded && wheelHit.point != Vector3.zero)
632 allWheelParticles[i].transform.position =
wheelHit.point + (.05f * transform.up);
633
634 }
635
636 }
637
638 /// <summary>
639 /// Drift.
640 /// </summary>
641 private void Drift() {
642
643 Vector3 relativeVelocity = transform.InverseTransformDirection
(Rigid.velocity);
644 float sqrVel = (relativeVelocity.x * relativeVelocity.x) /
50f;
645
646 if (wheelHit.forwardSlip > 0)
647 sqrVel += (Mathf.Abs(wheelHit.forwardSlip));
648
649 if (CarController.wheelTypeChoise ==
RCC_CarControllerV3.WheelType.RWD) {
650
651 // Forward
652 if (WheelCollider ==
CarController.FrontLeftWheelCollider.WheelCollider ||
WheelCollider ==
CarController.FrontRightWheelCollider.WheelCollider) {
653
654 forwardFrictionCurve.extremumValue = Mathf.Clamp
(forwardFrictionCurve_Org.extremumValue - sqrVel,
minForwardStiffness / 1f, maxForwardStiffness);
655 forwardFrictionCurve.asymptoteValue = Mathf.Clamp
(forwardFrictionCurve_Org.asymptoteValue - (sqrVel /
1f), minForwardStiffness / 1f,
maxForwardStiffness); ;
656
657 } else {
658
659 forwardFrictionCurve.extremumValue = Mathf.Clamp
(forwardFrictionCurve_Org.extremumValue - sqrVel,
minForwardStiffness, maxForwardStiffness);
660 forwardFrictionCurve.asymptoteValue = Mathf.Clamp
(forwardFrictionCurve_Org.asymptoteValue - (sqrVel /
1f), minForwardStiffness, maxForwardStiffness);
661
662 }
663
664 // Sideways
665 if (WheelCollider ==
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 16
CarController.FrontLeftWheelCollider.WheelCollider ||
WheelCollider ==
CarController.FrontRightWheelCollider.WheelCollider) {
666
667 sidewaysFrictionCurve.extremumValue = Mathf.Clamp
(sidewaysFrictionCurve_Org.extremumValue - sqrVel,
minSidewaysStiffness, maxSidewaysStiffness);
668 sidewaysFrictionCurve.asymptoteValue = Mathf.Clamp
(sidewaysFrictionCurve_Org.asymptoteValue - (sqrVel /
1f), minSidewaysStiffness, maxSidewaysStiffness);
669
670 } else {
671
672 sidewaysFrictionCurve.extremumValue = Mathf.Clamp
(sidewaysFrictionCurve_Org.extremumValue - sqrVel,
minSidewaysStiffness, maxSidewaysStiffness);
673 sidewaysFrictionCurve.asymptoteValue = Mathf.Clamp
(sidewaysFrictionCurve_Org.asymptoteValue - (sqrVel /
1f), minSidewaysStiffness, maxSidewaysStiffness);
674
675 }
676
677 } else {
678
679 if (WheelCollider ==
CarController.FrontLeftWheelCollider.WheelCollider ||
WheelCollider ==
CarController.FrontRightWheelCollider.WheelCollider) {
680
681 // Forward
682 forwardFrictionCurve.extremumValue = Mathf.Clamp
(forwardFrictionCurve_Org.extremumValue - sqrVel,
minForwardStiffness / 1f, maxForwardStiffness);
683 forwardFrictionCurve.asymptoteValue = Mathf.Clamp
(forwardFrictionCurve_Org.asymptoteValue - (sqrVel /
1f), minForwardStiffness / 1f, maxForwardStiffness);
684
685 } else {
686
687 forwardFrictionCurve.extremumValue = Mathf.Clamp
(forwardFrictionCurve_Org.extremumValue - sqrVel,
minForwardStiffness, maxForwardStiffness);
688 forwardFrictionCurve.asymptoteValue = Mathf.Clamp
(forwardFrictionCurve_Org.asymptoteValue - (sqrVel /
1f), minForwardStiffness, maxForwardStiffness);
689
690 }
691
692 // Sideways
693 sidewaysFrictionCurve.extremumValue = Mathf.Clamp
(sidewaysFrictionCurve_Org.extremumValue - sqrVel,
minSidewaysStiffness, maxSidewaysStiffness);
694 sidewaysFrictionCurve.asymptoteValue = Mathf.Clamp
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 17
(sidewaysFrictionCurve_Org.asymptoteValue - (sqrVel /
1f), minSidewaysStiffness, maxSidewaysStiffness);
695
696 }
697
698 }
699
700 /// <summary>
701 /// Audio.
702 /// </summary>
703 private void Audio() {
704
705 // Set audioclip to ground physic material sound.
706 audioClip = RCC_GroundMaterials.Instance.frictions
[groundIndex].groundSound;
707 audioVolume = RCC_GroundMaterials.Instance.frictions
[groundIndex].volume;
708
709 // If total slip is high enough...
710 if (totalSlip > RCC_GroundMaterials.Instance.frictions
[groundIndex].slip) {
711
712 // Assigning corresponding audio clip.
713 if (audioSource.clip != audioClip)
714 audioSource.clip = audioClip;
715
716 // Playing it.
717 if (!audioSource.isPlaying)
718 audioSource.Play();
719
720 // If vehicle is moving, set volume and pitch. Otherwise
set them to 0.
721 if (Rigid.velocity.magnitude > 1f) {
722
723 audioSource.volume = Mathf.Lerp(0f, audioVolume,
totalSlip);
724 audioSource.pitch = Mathf.Lerp(1f, .8f,
audioSource.volume);
725
726 } else {
727
728 audioSource.volume = 0f;
729
730 }
731
732 } else {
733
734 audioSource.volume = 0f;
735
736 // If volume is minimal and audio is still playing, stop.
737 if (audioSource.volume <= .05f && audioSource.isPlaying)
738 audioSource.Stop();
739
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 18
740 }
741
742 // Calculating bump force.
743 bumpForce = wheelHit.force - oldForce;
744
745 // If bump force is high enough, play bump SFX.
746 if ((bumpForce) >= 5000f) {
747
748 // Creating and playing audiosource for bump SFX.
749 AudioSource bumpSound = NewAudioSource
(RCC_Settings.Instance.audioMixer,
CarController.gameObject, "Bump Sound AudioSource", 5f,
50f, (bumpForce - 5000f) / 3000f,
RCC_Settings.Instance.bumpClip, false, true, true);
750 bumpSound.pitch = Random.Range(.9f, 1.1f);
751
752 }
753
754 oldForce = wheelHit.force;
755
756 }
757
758 /// <summary>
759 /// Returns true if one of the wheel is slipping.
760 /// </summary>
761 /// <returns><c>true</c>, if skidding was ised, <c>false</c>
otherwise.</returns>
762 public bool IsSkidding() {
763
764 for (int i = 0; i < CarController.AllWheelColliders.Length; i+
+) {
765
766 if (CarController.AllWheelColliders[i].totalSlip >
RCC_GroundMaterials.Instance.frictions[groundIndex].slip)
767 return true;
768
769 }
770
771 return false;
772
773 }
774
775 /// <summary>
776 /// Applies the motor torque.
777 /// </summary>
778 /// <param name="torque">Torque.</param>
779 public void ApplyMotorTorque(float torque) {
780
781 // If TCS is enabled, checks forward slip. If wheel is losing
traction, don't apply torque.
782 if (CarController.TCS) {
783
784 if (Mathf.Abs(WheelCollider.rpm) >= 1) {
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 19
785
786 if (Mathf.Abs(wheelSlipAmountForward) >
RCC_GroundMaterials.Instance.frictions
[groundIndex].slip) {
787
788 CarController.TCSAct = true;
789
790 torque -= Mathf.Clamp(torque * (Mathf.Abs
(wheelSlipAmountForward)) *
CarController.TCSStrength, -Mathf.Infinity,
Mathf.Infinity);
791
792 if (WheelCollider.rpm > 1) {
793
794 torque -= Mathf.Clamp(torque * (Mathf.Abs
(wheelSlipAmountForward)) *
CarController.TCSStrength, 0f, Mathf.Infinity);
795 torque = Mathf.Clamp(torque, 0f,
Mathf.Infinity);
796
797 } else {
798
799 torque += Mathf.Clamp(-torque * (Mathf.Abs
(wheelSlipAmountForward)) *
CarController.TCSStrength, 0f, Mathf.Infinity);
800 torque = Mathf.Clamp(torque, -Mathf.Infinity,
0f);
801
802 }
803
804 } else {
805
806 CarController.TCSAct = false;
807
808 }
809
810 } else {
811
812 CarController.TCSAct = false;
813
814 }
815
816 }
817
818 if (CheckOvertorque())
819 torque = 0;
820
821 if (Mathf.Abs(torque) > 1f)
822 WheelCollider.motorTorque = torque;
823 else
824 WheelCollider.motorTorque = 0f;
825
826 }
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 20
827
828 /// <summary>
829 /// Applies the steering.
830 /// </summary>
831 /// <param name="steerInput">Steer input.</param>
832 /// <param name="angle">Angle.</param>
833 public void ApplySteering(float steerInput, float angle) {
834
835 // Ackerman steering formula.
836 if (steerInput > 0f) {
837
838 if (transform.localPosition.x < 0)
839 WheelCollider.steerAngle = (Mathf.Deg2Rad * angle *
2.55f) * (Mathf.Rad2Deg * Mathf.Atan(2.55f / (6 +
(1.5f / 2))) * steerInput);
840 else
841 WheelCollider.steerAngle = (Mathf.Deg2Rad * angle *
2.55f) * (Mathf.Rad2Deg * Mathf.Atan(2.55f / (6 -
(1.5f / 2))) * steerInput);
842
843 } else if (steerInput < 0f) {
844
845 if (transform.localPosition.x < 0)
846 WheelCollider.steerAngle = (Mathf.Deg2Rad * angle *
2.55f) * (Mathf.Rad2Deg * Mathf.Atan(2.55f / (6 -
(1.5f / 2))) * steerInput);
847 else
848 WheelCollider.steerAngle = (Mathf.Deg2Rad * angle *
2.55f) * (Mathf.Rad2Deg * Mathf.Atan(2.55f / (6 +
(1.5f / 2))) * steerInput);
849
850 } else {
851
852 WheelCollider.steerAngle = 0f;
853
854 }
855
856 if (transform.localPosition.x < 0)
857 WheelCollider.steerAngle += toe;
858 else
859 WheelCollider.steerAngle -= toe;
860
861 }
862
863 /// <summary>
864 /// Applies the brake torque.
865 /// </summary>
866 /// <param name="torque">Torque.</param>
867 public void ApplyBrakeTorque(float torque) {
868
869 // If ABS is enabled, checks forward slip. If wheel is losing
traction, don't apply torque.
870 if (CarController.ABS && CarController.handbrakeInput <= .1f)
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 21
{
871
872 if ((Mathf.Abs(wheelHit.forwardSlip) * Mathf.Clamp01
(torque)) >= CarController.ABSThreshold) {
873
874 CarController.ABSAct = true;
875 torque = 0;
876
877 } else {
878
879 CarController.ABSAct = false;
880
881 }
882
883 }
884
885 if (Mathf.Abs(torque) > 1f)
886 WheelCollider.brakeTorque = torque;
887 else
888 WheelCollider.brakeTorque = 0f;
889
890 }
891
892 /// <summary>
893 /// Converts to splat map coordinate.
894 /// </summary>
895 /// <returns>The to splat map coordinate.</returns>
896 /// <param name="playerPos">Player position.</param>
897 private Vector3 ConvertToSplatMapCoordinate(Terrain terrain,
Vector3 playerPos) {
898
899 Vector3 vecRet = new Vector3();
900 Vector3 terPosition = terrain.transform.position;
901 vecRet.x = ((playerPos.x - terPosition.x) /
terrain.terrainData.size.x) *
terrain.terrainData.alphamapWidth;
902 vecRet.z = ((playerPos.z - terPosition.z) /
terrain.terrainData.size.z) *
terrain.terrainData.alphamapHeight;
903 return vecRet;
904
905 }
906
907 /// <summary>
908 /// Gets the index of the ground material.
909 /// </summary>
910 /// <returns>The ground material index.</returns>
911 private void GroundMaterial() {
912
913 isGrounded = WheelCollider.GetGroundHit(out wheelHit);
914
915 if (!isGrounded || wheelHit.point == Vector3.zero ||
wheelHit.collider == null) {
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 22
916
917 groundIndex = 0;
918 return;
919
920 }
921
922 for (int i = 0; i <
RCC_GroundMaterials.Instance.frictions.Length; i++) {
923
924 if (wheelHit.collider.sharedMaterial ==
RCC_GroundMaterials.Instance.frictions[i].groundMaterial)
{
925
926 groundIndex = i;
927 return;
928
929 }
930
931 }
932
933 // If ground pyhsic material is not one of the ground material
in Configurable Ground Materials, check if we are on
terrain collider...
934 if (!RCC_SceneManager.Instance.terrainsInitialized) {
935
936 groundIndex = 0;
937 return;
938
939 }
940
941 for (int i = 0; i <
RCC_GroundMaterials.Instance.terrainFrictions.Length; i++) {
942
943 if (wheelHit.collider.sharedMaterial ==
RCC_GroundMaterials.Instance.terrainFrictions
[i].groundMaterial) {
944
945 RCC_SceneManager.Terrains currentTerrain = null;
946
947 for (int l = 0; l <
RCC_SceneManager.Instance.terrains.Length; l++) {
948
949 if (RCC_SceneManager.Instance.terrains
[l].terrainCollider ==
RCC_GroundMaterials.Instance.terrainFrictions
[i].groundMaterial) {
950
951 currentTerrain =
RCC_SceneManager.Instance.terrains[l];
952 break;
953
954 }
955
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 23
956 }
957
958 if (currentTerrain != null) {
959
960 Vector3 playerPos = transform.position;
961 Vector3 TerrainCord = ConvertToSplatMapCoordinate
(currentTerrain.terrain, playerPos);
962 float comp = 0f;
963
964 for (int k = 0; k < currentTerrain.mNumTextures; k
++) {
965
966 if (comp < currentTerrain.mSplatmapData[(int)
TerrainCord.z, (int)TerrainCord.x, k])
967 groundIndex = k;
968
969 }
970
971 groundIndex =
RCC_GroundMaterials.Instance.terrainFrictions
[i].splatmapIndexes[groundIndex].index;
972 return;
973
974 }
975
976 }
977
978 }
979
980 groundIndex = 0;
981
982 }
983
984 /// <summary>
985 /// Checking deflated wheel.
986 /// </summary>
987 private void CheckDeflate() {
988
989 if (deflated) {
990
991 if (!flatSource)
992 flatSource = NewAudioSource(gameObject,
FlatAudio.name, 1f, 15f, .5f, FlatAudio, true, false,
false);
993
994 flatSource.volume = Mathf.Clamp01(Mathf.Abs
(WheelCollider.rpm * .001f));
995 flatSource.volume *= isGrounded ? 1f : 0f;
996
997 if (!flatSource.isPlaying)
998 flatSource.Play();
999
1000 } else {
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 24
1001
1002 if (flatSource && flatSource.isPlaying)
1003 flatSource.Stop();
1004
1005 }
1006
1007 if (_wheelDeflateParticles != null) {
1008
1009 ParticleSystem.EmissionModule em =
_wheelDeflateParticles.emission;
1010
1011 if (deflated) {
1012
1013 if (WheelCollider.rpm > 100f && isGrounded)
1014 em.enabled = true;
1015 else
1016 em.enabled = false;
1017
1018 } else {
1019
1020 em.enabled = false;
1021
1022 }
1023
1024 }
1025
1026 if (!isGrounded || wheelHit.point == Vector3.zero ||
wheelHit.collider == null)
1027 return;
1028
1029 for (int i = 0; i <
RCC_GroundMaterials.Instance.frictions.Length; i++) {
1030
1031 if (wheelHit.collider.sharedMaterial ==
RCC_GroundMaterials.Instance.frictions[i].groundMaterial)
{
1032
1033 if (RCC_GroundMaterials.Instance.frictions[i].deflate)
1034 Deflate();
1035
1036 }
1037
1038 }
1039
1040 }
1041
1042 /// <summary>
1043 /// Checks if overtorque applying.
1044 /// </summary>
1045 /// <returns><c>true</c>, if torque was overed, <c>false</c>
otherwise.</returns>
1046 private bool CheckOvertorque() {
1047
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 25
1048 if (CarController.speed > CarController.maxspeed || !
CarController.engineRunning)
1049 return true;
1050
1051 if (CarController.speed > CarController.gears
[CarController.currentGear].maxSpeed &&
CarController.engineRPM >= (CarController.maxEngineRPM
* .985f))
1052 return true;
1053
1054 return false;
1055
1056 }
1057
1058 /// <summary>
1059 /// Sets a new friction to WheelCollider.
1060 /// </summary>
1061 /// <returns>The friction curves.</returns>
1062 /// <param name="curve">Curve.</param>
1063 /// <param name="extremumSlip">Extremum slip.</param>
1064 /// <param name="extremumValue">Extremum value.</param>
1065 /// <param name="asymptoteSlip">Asymptote slip.</param>
1066 /// <param name="asymptoteValue">Asymptote value.</param>
1067 public WheelFrictionCurve SetFrictionCurves(WheelFrictionCurve
curve, float extremumSlip, float extremumValue, float
asymptoteSlip, float asymptoteValue) {
1068
1069 WheelFrictionCurve newCurve = curve;
1070
1071 newCurve.extremumSlip = extremumSlip;
1072 newCurve.extremumValue = extremumValue;
1073 newCurve.asymptoteSlip = asymptoteSlip;
1074 newCurve.asymptoteValue = asymptoteValue;
1075
1076 return newCurve;
1077
1078 }
1079
1080 /// <summary>
1081 /// Deflates the wheel.
1082 /// </summary>
1083 public void Deflate() {
1084
1085 if (deflated)
1086 return;
1087
1088 deflated = true;
1089
1090 if (defRadius == -1)
1091 defRadius = WheelCollider.radius;
1092
1093 WheelCollider.radius = defRadius * deflateRadiusMultiplier;
1094
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 26
1095 if (DeflateAudio)
1096 NewAudioSource(gameObject, DeflateAudio.name, 5f, 50f, 1f,
DeflateAudio, false, true, true);
1097
1098 if (_wheelDeflateParticles == null && WheelDeflateParticles) {
1099
1100 GameObject ps = Instantiate
(WheelDeflateParticles.gameObject, transform.position,
transform.rotation);
1101 _wheelDeflateParticles = ps.GetComponent<ParticleSystem>
();
1102 _wheelDeflateParticles.transform.SetParent(transform,
false);
1103 _wheelDeflateParticles.transform.localPosition = new
Vector3(0f, -.2f, 0f);
1104 _wheelDeflateParticles.transform.localRotation =
Quaternion.identity;
1105
1106 }
1107
1108 CarController.Rigid.AddForceAtPosition(transform.right *
Random.Range(-1f, 1f) * 30f, transform.position,
ForceMode.Acceleration);
1109
1110 }
1111
1112 /// <summary>
1113 /// Inflates the wheel.
1114 /// </summary>
1115 public void Inflate() {
1116
1117 if (!deflated)
1118 return;
1119
1120 deflated = false;
1121
1122 if (defRadius != -1)
1123 WheelCollider.radius = defRadius;
1124
1125 if (InflateAudio)
1126 NewAudioSource(gameObject, InflateAudio.name, 5f, 50f, 1f,
InflateAudio, false, true, true);
1127
1128 }
1129
1130 private void OnDisable() {
1131
1132 RCC_SceneManager.OnBehaviorChanged -= UpdateWheelFrictions;
1133
1134 if (wheelModel)
1135 wheelModel.gameObject.SetActive(false);
1136
1137 // Resetting values on disable.
...alisticCarControllerV3\Scripts\RCC_WheelCollider.cs 27
1138 wheelSlipAmountForward = 0f;
1139 wheelSlipAmountSideways = 0f;
1140 totalSlip = 0f;
1141 bumpForce = 0f;
1142 oldForce = 0f;
1143
1144 if (audioSource) {
1145
1146 audioSource.volume = 0f;
1147 audioSource.Stop();
1148
1149 }
1150
1151 WheelCollider.motorTorque = 0f;
1152 WheelCollider.brakeTorque = 0f;
1153 WheelCollider.steerAngle = 0f;
1154
1155 }
1156
1157 /// <summary>
1158 /// Raises the draw gizmos event.
1159 /// </summary>
1160 private void OnDrawGizmos() {
1161
1162 #if UNITY_EDITOR
1163 if (Application.isPlaying) {
1164
1165 WheelCollider.GetGroundHit(out WheelHit hit);
1166
1167 // Drawing gizmos for wheel forces and slips.
1168 float extension = (-
WheelCollider.transform.InverseTransformPoint
(hit.point).y - (WheelCollider.radius *
transform.lossyScale.y)) /
WheelCollider.suspensionDistance;
1169 Debug.DrawLine(hit.point, hit.point + transform.up *
(hit.force / Rigid.mass), extension <= 0.0 ?
Color.magenta : Color.white);
1170 Debug.DrawLine(hit.point, hit.point - transform.forward *
hit.forwardSlip * 2f, Color.green);
1171 Debug.DrawLine(hit.point, hit.point - transform.right *
hit.sidewaysSlip * 2f, Color.red);
1172
1173 }
1174 #endif
1175
1176 }
1177
1178 }