0
\$\begingroup\$

I have a gun firing sound audio clip and I want this to be played repeatedly while the mouse left button is pressed, like a machine gun where there is automatic firing.

If I do something like:

void Update()
    {
        if (gunScript.gotGun)
        {
            var mouse = Mouse.current;
            var gamepad = Gamepad.current;

            if (mouse != null)
            {
                if (mouse.leftButton.isPressed)
                {
                    gunFireSound.Play();
                }
            }
        }

        
    }

It plays extremely rapidly as that's how the code gets executed very fast. How do I add a small delay or is there a better way to achieve this?

I also thought of an alternative but it doesn't play it fast enough. (the alternative was an if statement to check if it is finished playing, and play it again)

Thanks in advance. :)

\$\endgroup\$
2
  • \$\begingroup\$ Does your audio clip play a single-fired shot, or is it a looping sound? You can deal with these two cases in two different ways. \$\endgroup\$
    – liggiorgio
    Jun 16 '20 at 12:13
  • \$\begingroup\$ It is a single fired shot. Maybe I should do what DMGregory said and put the file in Audacity and get it so that the looping sounds right, but I'll try the other solutions first. \$\endgroup\$
    – Jiehfeng
    Jun 16 '20 at 12:16
1
\$\begingroup\$

You can manage this using a coroutine. For example:

private IEnumerator GunShotSound_Coroutine()
{
    while(mouse.leftButton.isPressed)
    {
        gunFireSound.Play();
        yield return new WaitForSeconds(1.0f);
    }
}

In the update function, you controlled if the leftbutton was pressed this frame and you start the coroutine.

if(Input.GetKeyDown(mouse.leftButton))
{
    StartCoroutine("GunShotSound_Coroutine");
}

I did not test this code but the idea is here :)

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Better to remove the quotation marks around the coroutine name so you can reference it directly, without reflection. This will also let it update correctly as code is refactored. \$\endgroup\$
    – DMGregory
    Jun 16 '20 at 12:07
  • \$\begingroup\$ Brilliant! This seems to be the fastest solution, I will check back on it. \$\endgroup\$
    – Jiehfeng
    Jun 16 '20 at 12:18
  • \$\begingroup\$ I just used the code and changed the seconds to 0.1f and it's perfect! Works like a charm, thank you all. :D \$\endgroup\$
    – Jiehfeng
    Jun 16 '20 at 12:25
2
\$\begingroup\$

The simplest thing to do is to check whether the audio source is still playing the previous sound, and play a new one only if it's done:

if(!gunFireSound.isPlaying)
    gunFireSound.Play();

But that might make your shots sound too far apart. So you might want to allow your new shot to interrupt the old one after a specified duration.

if(!gunFireSound.isPlaying || gunFireSound.timeSamples > gunFireInterrupt)
    gunFireSound.Play();

Here timeSamples is a high-precision count of the individual audio samples played so far.

You can also use PlayScheduled to queue-up the next iteration of the shot at a fixed interval from the previous one, to make the rhythm of shots more uniform despite variances in frame timing.

But the best solution is probably to have a looping machine gun sound that you can start playing on press, and transition into a tail-off sound on release. This will give you the best control over the sound and rhythm of the shots, and avoid artifacts from interrupting a sound in progress.

\$\endgroup\$
4
  • \$\begingroup\$ Thanks! I am a little confused over the timeSamples and gunFireInterrupt. How do I control the timeSamples and the other variable if you don't mind me asking? :) Also that sounds like a great idea, I will see if I can get it to work that way. \$\endgroup\$
    – Jiehfeng
    Jun 16 '20 at 12:17
  • \$\begingroup\$ You just set gunFireInterrupt to an integer high enough for your needs. For instance, a 44 kHz audio clip uses 44 000 samples per second. So if you want to be able to interrupt it after half a second you'd set gunFireInterrupt to 22 000 \$\endgroup\$
    – DMGregory
    Jun 16 '20 at 12:20
  • \$\begingroup\$ I see, thank you very much! I will look into this more. \$\endgroup\$
    – Jiehfeng
    Jun 16 '20 at 12:24
  • \$\begingroup\$ The looping sound approach works best for weapons with high ROF, whereas I prefer to sync the SFX playing to the actual logic (e.g. instantiating the bullet object/trail/whatever) for semi-automatic weapons or low ROFs. \$\endgroup\$
    – liggiorgio
    Jun 16 '20 at 12:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.