Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Change car sound with c#

Discussion in 'Scripting' started by SemdeBakker, Nov 23, 2020.

  1. SemdeBakker

    SemdeBakker

    Joined:
    Oct 14, 2020
    Posts:
    4
    Hi,

    I am making a race game and I am trying to change the car sound if I 'step' on the gas. So I figured that part out but if a start the game I hear it for only a second, then it diseapears. I do not know what's going on, I have tried many things to fix it. Hopefully, there is somebody who knows what I am doing wrong. My code is the following:

    Code (CSharp):
    1.     private void SwitchSound()
    2.     {
    3.         if(onGas)
    4.         {
    5.             if(counterAccelerate == 0)
    6.             {
    7.                 AudioSource audio = GetComponent<AudioSource>();
    8.                 audio.clip = carAccelerateSound;
    9.                 audio.Play();
    10.             }
    11.  
    12.             counterAccelerate++;
    13.             if(counterAccelerate == 200)
    14.             {
    15.                 counterAccelerate = 0;
    16.             }
    17.         }
    18.         else
    19.         {
    20.             AudioSource audio = GetComponent<AudioSource>();
    21.             audio.clip = carEngineSound;
    22.             audio.Play();
    23.         }
    24.     }
    SwitchSound(); is called in the Update().
    onGas is a bool that will become true is pressed on arrow up.
    The counter is made because I want to play the clip every second again if pressed on arrow up of course.
    CarEngineSound is a clip of a car just running and CarAccelerateSound is a clip of a car accelerating.

    If you have any tips and tricks whatsoever. Do not hesitate to repy :)



    S.J.
     
  2. Ray_Sovranti

    Ray_Sovranti

    Joined:
    Oct 28, 2020
    Posts:
    172
    Based on the numbers there... you seem to be expecting the game to be running at 200 frames per second?

    If you want to do something every second, you should track the amount of time that's passed (using a float and adding Time.deltaTime each frame, for example) instead of counting the number of frames.

    But, more simply, you should just set audio.loop to "true" to get the sound to loop, then you don't have to deal with any of that ^ above or deal with the annoying gap each time you replay the sound.
     
    PraetorBlue likes this.
  3. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,722
    Since you're calling this in Update I'd guess you're calling audio source.Play every frame. Every time you call it it restarts the sound that's playing. That's why it doesn't sound right
     
    Joe-Censored likes this.
  4. SemdeBakker

    SemdeBakker

    Joined:
    Oct 14, 2020
    Posts:
    4
    Thanks but I already have it on loop, I am doing that because then the clip will replay every frame. So he should only replay the clip if the clip ended.

    And PraetorBlue. You are right thats why I added the counter. I also added a counter at the engine sound but I still hear noting. Is there an other way to prevent this?
     
  5. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I don't see anywhere in this code where you are checking if the clip has ended. If SwitchSound() gets called 200 times it restarts playing the audio from the beginning. For all I know you have hardly anything in your scene, causing you to get like 4000 FPS. If that was the case you'd be restarting the sound 20 times per second. If there was any dead air at the beginning of the clip, you'd very likely not hear a thing.

    I'd redesign this to get rid of the counter, and just check if the audio source is playing. If not then you tell it to play. Also you should cache the audiosource. Calling GetComponent every frame is an unnecessary use of CPU.

    https://docs.unity3d.com/ScriptReference/AudioSource-isPlaying.html
     
    PraetorBlue likes this.
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    You probably aren't going to get what you want starting the clip at the moment the gas is applied.

    Instead use two looping clips, one of the engine without load, one of the engine with load, but the same RPM.

    Start them both simultaneously and keep them on two separate audio source instances. Doesn't matter if they both loop at the same precise instant; in fact it might be better if they don't.

    Then as your RPM goes up with speed, smoothly move the pitch up for both of them at the same rate.

    When the gas is ON, smoothly increase the volume of the loaded engine sound vs the unloaded engine sound.

    That way when you're at speed and chop power, the pitch will slowly wind down, but the timbre of the engine will smoothly tween back to the unloaded engine sound, as you would expect when load is removed.

    I'd start with just loaded and unloaded sounds, but you can expand it to a whole cascading range of synchronized simultaneously-playing engine sounds, such as starting from idle, then driving without much load, medium load, high load, etc.
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    Actually I have been meaning to put such an engine on/off demo package together... See enclosed package.

    Also, as outlined above, below is the basic script for a loaded and unloaded engine. If you use real engine sounds (I don't have any I can post publicly), it works pretty nice. I just used Audacity to come up with some different-sounding engine noises based on square / sawtooth waveforms.



    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. // @kurtdekker
    7.  
    8. public class EngineNoise : MonoBehaviour
    9. {
    10.     public AudioSource EngineLowLoad;
    11.     public AudioSource EngineHighLoad;
    12.  
    13.     const float RPMScale = 1700;
    14.  
    15.     public Text TextRPM;
    16.  
    17.     void Start ()
    18.     {
    19.         EngineLowLoad.loop = true;
    20.         EngineLowLoad.Play();
    21.  
    22.         EngineHighLoad.loop = true;
    23.         EngineHighLoad.Play();
    24.  
    25.         rpm = 1.0f;
    26.     }
    27.  
    28.     float rpm;
    29.     float power;
    30.  
    31.     void Update ()
    32.     {
    33.         float gasPedal = 0.0f;
    34.  
    35.         if (Input.GetKey( KeyCode.Space))
    36.         {
    37.             gasPedal = 1.0f;
    38.         }
    39.  
    40.         if (Input.GetKey( KeyCode.Alpha1))
    41.         {
    42.             gasPedal = 0.5f;
    43.         }
    44.  
    45.         // Power tweens towards the gasPedal setting
    46.         // This tween is fairly rapid when gas is added/removed
    47.         power = Mathf.MoveTowards( power, gasPedal, 8.0f * Time.deltaTime);
    48.  
    49.         // fairly low volume on the unloaded engine, and it fades down
    50.         float volLowLoad = Mathf.Lerp( 0.2f, 0.1f, power);
    51.  
    52.         // zero volume on high load engine until you get on the gas
    53.         float volHighLoad = Mathf.Lerp( 0.0f, 1.0f, power);
    54.  
    55.         EngineLowLoad.volume = volLowLoad;
    56.         EngineHighLoad.volume = volHighLoad;
    57.  
    58.         // The engine instantly WANTS to be at an RPM according to gas
    59.         float desiredRPM = 1.0f + 2.0f * gasPedal;
    60.  
    61.         // But the car and engine have momentum and can only gradually get there
    62.         rpm = Mathf.Lerp( rpm, desiredRPM, 0.25f * Time.deltaTime);
    63.  
    64.         // It also has a tiny linear term for moving towards goal,
    65.         // otherwise it only asymptotically approaches the goal forever.
    66.         rpm = Mathf.MoveTowards( rpm, desiredRPM, 0.05f * Time.deltaTime);
    67.  
    68.         // exponential sounds better!
    69.         float pitch = Mathf.Pow( 2, rpm);
    70.  
    71.         // pitch of both go up and down in sync
    72.         EngineLowLoad.pitch = pitch;
    73.         EngineHighLoad.pitch = pitch;
    74.  
    75.         TextRPM.color = Color.Lerp( Color.green, Color.yellow, power);
    76.  
    77.         int revs = (int)(rpm * RPMScale);
    78.         TextRPM.text = System.String.Format( "RPM: {0}", revs);
    79.     }
    80. }
     

    Attached Files:

    Last edited: Nov 24, 2020
  8. SemdeBakker

    SemdeBakker

    Joined:
    Oct 14, 2020
    Posts:
    4
     
    Kurt-Dekker likes this.
  9. SemdeBakker

    SemdeBakker

    Joined:
    Oct 14, 2020
    Posts:
    4
    I use the WheelCollider component for my car, can I use the same? But then with
    wheel.collider.rpm?

    I want somethings like this:


    (only the accelerate sound (on 0:15) and the engine sound when the car is on but not driving)
    Can I do that with two engine sounds like you said?


    :)
     
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    You would need to get the
    .angularVelocity
    of the Rigidbody associated with the wheel collider, then scale it so that its value is between 0.0f and 1.0f and feed it into the code above.

    Look up all those things, especially how angular velocity is. It's a vector, which means its direction is the axis of spin, so most likely the local axis sticking straight out of your hubcap, and its magnitude is the rate of rotation.

    This may or may not work well, especially if the wheels lose traction. You might have better luck just using the magnitude of the car rigidbody .velocity field, but definitely experiment.