CarAudio.cs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. using System;
  2. using UnityEngine;
  3. using Random = UnityEngine.Random;
  4. namespace UnityStandardAssets.Vehicles.Car
  5. {
  6. [RequireComponent(typeof (CarController))]
  7. public class CarAudio : MonoBehaviour
  8. {
  9. // This script reads some of the car's current properties and plays sounds accordingly.
  10. // The engine sound can be a simple single clip which is looped and pitched, or it
  11. // can be a crossfaded blend of four clips which represent the timbre of the engine
  12. // at different RPM and Throttle state.
  13. // the engine clips should all be a steady pitch, not rising or falling.
  14. // when using four channel engine crossfading, the four clips should be:
  15. // lowAccelClip : The engine at low revs, with throttle open (i.e. begining acceleration at very low speed)
  16. // highAccelClip : Thenengine at high revs, with throttle open (i.e. accelerating, but almost at max speed)
  17. // lowDecelClip : The engine at low revs, with throttle at minimum (i.e. idling or engine-braking at very low speed)
  18. // highDecelClip : Thenengine at high revs, with throttle at minimum (i.e. engine-braking at very high speed)
  19. // For proper crossfading, the clips pitches should all match, with an octave offset between low and high.
  20. public enum EngineAudioOptions // Options for the engine audio
  21. {
  22. Simple, // Simple style audio
  23. FourChannel // four Channel audio
  24. }
  25. public EngineAudioOptions engineSoundStyle = EngineAudioOptions.FourChannel;// Set the default audio options to be four channel
  26. public AudioClip lowAccelClip; // Audio clip for low acceleration
  27. public AudioClip lowDecelClip; // Audio clip for low deceleration
  28. public AudioClip highAccelClip; // Audio clip for high acceleration
  29. public AudioClip highDecelClip; // Audio clip for high deceleration
  30. public float pitchMultiplier = 1f; // Used for altering the pitch of audio clips
  31. public float lowPitchMin = 1f; // The lowest possible pitch for the low sounds
  32. public float lowPitchMax = 6f; // The highest possible pitch for the low sounds
  33. public float highPitchMultiplier = 0.25f; // Used for altering the pitch of high sounds
  34. public float maxRolloffDistance = 500; // The maximum distance where rollof starts to take place
  35. public float dopplerLevel = 1; // The mount of doppler effect used in the audio
  36. public bool useDoppler = true; // Toggle for using doppler
  37. private AudioSource m_LowAccel; // Source for the low acceleration sounds
  38. private AudioSource m_LowDecel; // Source for the low deceleration sounds
  39. private AudioSource m_HighAccel; // Source for the high acceleration sounds
  40. private AudioSource m_HighDecel; // Source for the high deceleration sounds
  41. private bool m_StartedSound; // flag for knowing if we have started sounds
  42. private CarController m_CarController; // Reference to car we are controlling
  43. private void StartSound()
  44. {
  45. // get the carcontroller ( this will not be null as we have require component)
  46. m_CarController = GetComponent<CarController>();
  47. // setup the simple audio source
  48. m_HighAccel = SetUpEngineAudioSource(highAccelClip);
  49. // if we have four channel audio setup the four audio sources
  50. if (engineSoundStyle == EngineAudioOptions.FourChannel)
  51. {
  52. m_LowAccel = SetUpEngineAudioSource(lowAccelClip);
  53. m_LowDecel = SetUpEngineAudioSource(lowDecelClip);
  54. m_HighDecel = SetUpEngineAudioSource(highDecelClip);
  55. }
  56. // flag that we have started the sounds playing
  57. m_StartedSound = true;
  58. }
  59. private void StopSound()
  60. {
  61. //Destroy all audio sources on this object:
  62. foreach (var source in GetComponents<AudioSource>())
  63. {
  64. Destroy(source);
  65. }
  66. m_StartedSound = false;
  67. }
  68. // Update is called once per frame
  69. private void Update()
  70. {
  71. // get the distance to main camera
  72. float camDist = (Camera.main.transform.position - transform.position).sqrMagnitude;
  73. // stop sound if the object is beyond the maximum roll off distance
  74. if (m_StartedSound && camDist > maxRolloffDistance*maxRolloffDistance)
  75. {
  76. StopSound();
  77. }
  78. // start the sound if not playing and it is nearer than the maximum distance
  79. if (!m_StartedSound && camDist < maxRolloffDistance*maxRolloffDistance)
  80. {
  81. StartSound();
  82. }
  83. if (m_StartedSound)
  84. {
  85. // The pitch is interpolated between the min and max values, according to the car's revs.
  86. float pitch = ULerp(lowPitchMin, lowPitchMax, m_CarController.Revs);
  87. // clamp to minimum pitch (note, not clamped to max for high revs while burning out)
  88. pitch = Mathf.Min(lowPitchMax, pitch);
  89. if (engineSoundStyle == EngineAudioOptions.Simple)
  90. {
  91. // for 1 channel engine sound, it's oh so simple:
  92. m_HighAccel.pitch = pitch*pitchMultiplier*highPitchMultiplier;
  93. m_HighAccel.dopplerLevel = useDoppler ? dopplerLevel : 0;
  94. m_HighAccel.volume = 1;
  95. }
  96. else
  97. {
  98. // for 4 channel engine sound, it's a little more complex:
  99. // adjust the pitches based on the multipliers
  100. m_LowAccel.pitch = pitch*pitchMultiplier;
  101. m_LowDecel.pitch = pitch*pitchMultiplier;
  102. m_HighAccel.pitch = pitch*highPitchMultiplier*pitchMultiplier;
  103. m_HighDecel.pitch = pitch*highPitchMultiplier*pitchMultiplier;
  104. // get values for fading the sounds based on the acceleration
  105. float accFade = Mathf.Abs(m_CarController.AccelInput);
  106. float decFade = 1 - accFade;
  107. // get the high fade value based on the cars revs
  108. float highFade = Mathf.InverseLerp(0.2f, 0.8f, m_CarController.Revs);
  109. float lowFade = 1 - highFade;
  110. // adjust the values to be more realistic
  111. highFade = 1 - ((1 - highFade)*(1 - highFade));
  112. lowFade = 1 - ((1 - lowFade)*(1 - lowFade));
  113. accFade = 1 - ((1 - accFade)*(1 - accFade));
  114. decFade = 1 - ((1 - decFade)*(1 - decFade));
  115. // adjust the source volumes based on the fade values
  116. m_LowAccel.volume = lowFade*accFade;
  117. m_LowDecel.volume = lowFade*decFade;
  118. m_HighAccel.volume = highFade*accFade;
  119. m_HighDecel.volume = highFade*decFade;
  120. // adjust the doppler levels
  121. m_HighAccel.dopplerLevel = useDoppler ? dopplerLevel : 0;
  122. m_LowAccel.dopplerLevel = useDoppler ? dopplerLevel : 0;
  123. m_HighDecel.dopplerLevel = useDoppler ? dopplerLevel : 0;
  124. m_LowDecel.dopplerLevel = useDoppler ? dopplerLevel : 0;
  125. }
  126. }
  127. }
  128. // sets up and adds new audio source to the gane object
  129. private AudioSource SetUpEngineAudioSource(AudioClip clip)
  130. {
  131. // create the new audio source component on the game object and set up its properties
  132. AudioSource source = gameObject.AddComponent<AudioSource>();
  133. source.clip = clip;
  134. source.volume = 0;
  135. source.loop = true;
  136. // start the clip from a random point
  137. source.time = Random.Range(0f, clip.length);
  138. source.Play();
  139. source.minDistance = 5;
  140. source.maxDistance = maxRolloffDistance;
  141. source.dopplerLevel = 0;
  142. return source;
  143. }
  144. // unclamped versions of Lerp and Inverse Lerp, to allow value to exceed the from-to range
  145. private static float ULerp(float from, float to, float value)
  146. {
  147. return (1.0f - value)*from + value*to;
  148. }
  149. }
  150. }