Changing the values of GetKeyDown when that key is actually down

Hey all,

I have power-ups on my top-down shooter and some of these are changing the fire rate of the player-gun. I am achieving this by some booleans and the sound of different fire modes is bound to the instated bullets. But one of the fire modes is like a minigun so it has 3 stages of sound. The Start, The Loop, and The End.
Now I wrote something like this to achieve a minigun effect.

 private void Fire()
    {
        if (Input.GetButtonDown("Jump")) 

        {
            rapidFireCoroutine = StartCoroutine(RapidFire());
            if (pUpMan.mGunThree)
            {
                aM.PlayOneShot("PlayerGun3Start");
                aM.PlaySound("PlayerGun3Loop");
            }else if (!pUpMan.mGunThree)
            {
                aM.StopSound("PlayerGun3Loop");

            }
           
        }
        if (Input.GetButtonUp("Jump"))
        {
            StopCoroutine(rapidFireCoroutine);
            if (pUpMan.mGunThree)
            {
                aM.StopSound("PlayerGun3Loop");
                aM.PlayOneShot("PlayerGun3End");
                
            }
            else if (!pUpMan.mGunThree)
            {
                aM.StopSound("PlayerGun3Loop");

            }
            animatorMuzzleFlash.SetFloat("Muzzle", 0.4f);
            animatorMuzzleFlash2.SetFloat("Muzzle", 0.4f);
            animatorMuzzleFlash3.SetFloat("Muzzle", 0.4f);
        }


    }

Now this being a shooter, there is a tendency to get the fire key down at the start of the game and never let go. If this is the case, the sound is not changing. What I mean is if the fire key is down and the player gets a minigun power-up,when the fire key is down, the block with the boolean(pUpMan.mGunThree) is not firing unless the player lets the key up and press again.

Is there a way around this?
Thanks in advance…Cheers…=)

Hi,

I’m not sure if I understood your problem correctly but if your gun is supposed to continue shooting when the player presses the button down, set the animation(?) to “loop”.

If you want to stop the shooting even though the player is still pressing the button down, you could stop the coroutine by calling StopCoroutine and by passing on rapidFireCoroutine, or you could have the coroutine stop itself by not having an endless loop implemented which cannot be quit.

Do you know what an UML diagram is? If not, look it up, please. Since your idea is relatively complex, it could make sense to draw a flowchart on paper and visualise your logic there before translating it to C#.

Hi again,

I am aware of what UML is but don’t know it in detail or used it before. I will definitely check it. I am trying to give a lot of information as I can when I form my questions but I also try to make it short so that won’t be boring or intimidating. But, I also feel that I can not communicate my problem so well…=/

My problem is not about shooting or the animation but the sound. Normally, the sound of the 3 different fire rates is instantiated with the bullets. When you press the fire button, a bullet gets instantiated with the corresponding sound. But for one of the fire rates(let’s call it the minigun), that you get with a power-up(it has a 20 seconds time limit) I wanted to have a 3-part sound. A starting sound of a minigun, and ending sound of the minigun, and the loop sound of the minigun.

So if the player gets a minigun power-up, the fire rate changes for 20 seconds and if they press the fire button at this time and keep it pressed, I want them to hear the start sound(PlayOneShot()), followed by the loop sound(Play() with loop active) and if they stop pressing the button the end sound(also PlayOneShot()). The code-block that I shared in my first post does what I explained with one exception.

If the player gets the minigun power-up and presses the fire button and never lets it go:
The start sound plays once, which is followed by the loop sound, which keeps playing until the player lets the fire button go even when the timer for the minigun power-up ends and the boolean of that (pUpMan.mGunThree) turns false.

If the player gets another firing power-up when the minigun-power-up is active and while the fire button is pressed:
The loop sound does not stop playing until the player lets the button go and presses it again.

If the player gets the minigun power-up while the fire button was pressed:
The start sound and loop never play until the player lets the fire button go and press it again.

Now this being a shooter game there is a tendency to press the fire button at the start of the game and never let it go until the player is dead or the level is done and there are no mechanisms to prevent this(like ammo, or the guns being overheated or something like this). So if this is the case(or similar) the sounds that I want the player to hear when they have the minigun do never play or doesn’t stop even when the firing type changes.

What I want is to achieve that even the player does not let go of the fire button when they get the power-up they would hear the sound of the start section and the loop section the minigun sound until the timer goes of and than stop the loop sound even when the player keeps pressing the fire button.

That’s usually the problem, which is the reason why I suggested an UML. In my personal opinion, it is much easier to visualise the idea/logic than to describe it because human languages come with a lot of “decoration” which make it difficult to “see” the underlying logic at the first glance. Your UML diagram does not have to be perfect as you don’t click on a button to have the program translate it to code. It’s just supposed to be a visual help.

Your description is perfectly fine, though. I think I understood your idea now. :slight_smile:

I took another look at your code, and I’m wondering if this works:

if (pUpMan.mGunThree)
{
    aM.PlayOneShot("PlayerGun3Start");
    aM.PlaySound("PlayerGun3Loop");
}

I’m asking because, actually, AudioSource components cannot play multiple sounds simultaneously.

You are using a coroutine, which makes sense. I cannot find it anywhere in this thread (maybe I missed it?) but you could easily solve your problem with yield instructions and a while loop. The first yield would implement a delay with the duration of the “start sound”. Then the while loop would check if the button is still pressed down, if the minigun is still allowed to shoot and if the audio source stopped playing, then play the sound on loop. And after the while loop was quit, it plays the “end sound”. That could be an idea.


The alternative would be to use animation events. They are covered in the Glitch Garden section. In that case, you could create three animation states: Start → Shooting → End. Each of them could call a method at the beginning which is supposed to play or check if a sound is being played. The transition between Shooting and End is triggered by a trigger. And that trigger is controlled by your code. If the player releases the fire button or if there is no ammo anymore (or whatever your idea is), you set the trigger to false (or true) and have the animator switch to the End state.

I’m asking because, actually , AudioSource components cannot play multiple sounds simultaneously.

I made an AudioManager game object which adds an audio source for each sound, according to a public class I created. I am playing all my sounds through that. But since I created that through different tutorials and documentation, I am not very well equipped to answer why they are playing simultaneously but they do…=)

I am aware of the animation events and I used them frequently in this project and that might be the answer to my problem and I might use that at the end but I would like to solve this through code if I can because I can not understand why this is not working.

This is the coroutine in Fire()


    IEnumerator RapidFire()
    {
        while (true)

        {


            if (pUpMan.mGunOne == true)
            {
                aM.StopSound("PlayerGun3Loop");
                if (pUpMan.damageUpIsActive)
                {
                    GameObject laserP = Instantiate(mGunBulletPowerdUp, firePosition.position, Quaternion.identity) as GameObject;
                    Debug.Log("PowerdUp");
                    laserP.GetComponent<Rigidbody2D>().velocity = new Vector2(0, projectileSpeed);
                    aM.PlayOneShot("DamageUp");
                    animatorMuzzleFlash.SetFloat("Muzzle", 0.6f);
                    //float periodNewOne = 1f;
                    //projectileFiringPeriod = periodNewOne;

                }
                else
                {
                    GameObject laser = Instantiate(mGunBullet, firePosition.position, Quaternion.identity) as GameObject;
                    laser.GetComponent<Rigidbody2D>().velocity = new Vector2(0, projectileSpeed);
                    aM.PlayOneShot("PlayerGun");
                    animatorMuzzleFlash.SetFloat("Muzzle", 0.6f);
                    //float periodNewOne = 1f;
                    //projectileFiringPeriod = periodNewOne;

                }

            }




            if (pUpMan.mGunTwo == true)
            {

                if (pUpMan.damageUpIsActive)
                {
                    GameObject laser = Instantiate(mGunBulletPowerdUp, firePosition2.position, Quaternion.identity) as GameObject;
                    aM.PlayOneShot("DamageUp");
                    GameObject laser2 = Instantiate(mGunBulletPowerdUp, firePosition3.position, Quaternion.identity) as GameObject;
                   aM.PlayOneShot("DamageUp");
                    laser.GetComponent<Rigidbody2D>().velocity = new Vector2(0, projectileSpeed);
                    laser2.GetComponent<Rigidbody2D>().velocity = new Vector2(0, projectileSpeed);
                    animatorMuzzleFlash2.SetFloat("Muzzle", 0.6f);
                    animatorMuzzleFlash3.SetFloat("Muzzle", 0.6f);
                    //yield return new WaitForSeconds(0.1f);

                }
                else
                {
                    GameObject laser = Instantiate(mGunBullet, firePosition2.position, Quaternion.identity) as GameObject;
                   aM.PlayOneShot("PlayerGun2");
                    GameObject laser2 = Instantiate(mGunBullet, firePosition3.position, Quaternion.identity) as GameObject;
                    //FindObjectOfType<AudioManager>().PlayOneShot("PlayerGun2");
                    laser.GetComponent<Rigidbody2D>().velocity = new Vector2(0, projectileSpeed);
                    laser2.GetComponent<Rigidbody2D>().velocity = new Vector2(0, projectileSpeed);
                    animatorMuzzleFlash2.SetFloat("Muzzle", 0.6f);
                    animatorMuzzleFlash3.SetFloat("Muzzle", 0.6f);
                    //yield return new WaitForSeconds(0.1f);

                }
     
            }



            if (pUpMan.mGunThree == true)
            {


               aM.PlaySound("PlayerGun3Loop");

                if (pUpMan.damageUpIsActive)
                {
                    GameObject laser = Instantiate(mGunBulletPowerdUp, firePosition.position, Quaternion.identity) as GameObject;
                    aM.PlayOneShot("DamageUp");
                    GameObject laser2 = Instantiate(mGunBulletPowerdUp, firePosition2.position, Quaternion.identity) as GameObject;
                    aM.PlayOneShot("DamageUp");
                    GameObject laser3 = Instantiate(mGunBulletPowerdUp, firePosition3.position, Quaternion.identity) as GameObject;
                   
                    laser.GetComponent<Rigidbody2D>().velocity = new Vector2(0, projectileSpeed);
                    laser2.GetComponent<Rigidbody2D>().velocity = new Vector2(0, projectileSpeed);
                    laser3.GetComponent<Rigidbody2D>().velocity = new Vector2(0, projectileSpeed);
                    animatorMuzzleFlash.SetFloat("Muzzle", 0.6f);
                    animatorMuzzleFlash2.SetFloat("Muzzle", 0.6f);
                    animatorMuzzleFlash3.SetFloat("Muzzle", 0.6f);
                    //float periodNewThree = 0.1f;
                    //projectileFiringPeriod = periodNewThree;

                }
                else
                {
                    GameObject laser = Instantiate(mGunBullet, firePosition.position, Quaternion.identity) as GameObject;

                    aM.PlayOneShot("PlayerGun");
               
                    GameObject laser2 = Instantiate(mGunBullet, firePosition2.position, Quaternion.identity) as GameObject;
                   // FindObjectOfType<AudioManager>().PlayOneShot("PlayerGun3");
                    GameObject laser3 = Instantiate(mGunBullet, firePosition3.position, Quaternion.identity) as GameObject;
                   // FindObjectOfType<AudioManager>().PlayOneShot("PlayerGun3");
                    laser.GetComponent<Rigidbody2D>().velocity = new Vector2(0, projectileSpeed);
                    laser2.GetComponent<Rigidbody2D>().velocity = new Vector2(0, projectileSpeed);
                    laser3.GetComponent<Rigidbody2D>().velocity = new Vector2(0, projectileSpeed);
                    animatorMuzzleFlash.SetFloat("Muzzle", 0.6f);
                    animatorMuzzleFlash2.SetFloat("Muzzle", 0.6f);
                    animatorMuzzleFlash3.SetFloat("Muzzle", 0.6f);
                    //float periodNewThree = 0.1f;
                    //projectileFiringPeriod = periodNewThree;
                }

            }

            yield return new WaitForSeconds(projectileFiringPeriod);

        }
        
    }

Now I solved the biggest problem by adding the loop sound inside if (pUpMan.mGunThree == true) and stop it inside if (pUpMan.mGunOne == true). (mGunOne is the default state and when the player gets a power-up, it stays active for a while and returns to the default state). In this case, if the player presses the button , the start and loop sounds are heard and if they release the button the loop sound stops, and the end sound is heard.
If they don’t release the button, after the power-up timer ends, the loop sound stops when the default state is active. They won’t hear the end sound in this case but I can live with that…=)

But still, I cannot understand why the boolean is not working to stop the sound.

 if (Input.GetButtonDown("Jump")) 

        {
            rapidFireCoroutine = StartCoroutine(RapidFire());
            if (pUpMan.mGunThree)
            {
                aM.PlayOneShot("PlayerGun3Start");
                aM.PlaySound("PlayerGun3Loop");
            }else if (!pUpMan.mGunThree)
            {
                aM.StopSound("PlayerGun3Loop");

            }

Is it when you press the button down that the block fires and keeps running until you release the button even some values inside the block is changing (like the boolean) but these values don’t register because it didn’t finish running the block which started when you first pressed the button and you never released it?

Isn’t this block being inside Update() runs it from the start every frame even the button is not released?

Have you already tried to add Debug.Logs to your code to see what is going on during runtime? At the moment, we are staring at the code but we do not know if your else-if block actually gets called. If it does not get called, StopSound would not get called either.

Which code? If the code is wrapped in an if-statement, it gets executed only if the if-condition has been evaluated to true. In the code snippet that you posted in your last reply, the StopSound method gets called only in the frame when the “Jump” button has been pressed down and if both pUpMan.mGunThree and pUpMan.mGunThree are false.

Maybe you need the GetButton method to check bools that might change their value while the player is pressing the button down.

Hi,

 private void Fire()
    {
        if (Input.GetButtonDown("Jump")) 

        {
            rapidFireCoroutine = StartCoroutine(RapidFire());
            if (pUpMan.mGunThree)
            {
                aM.PlayOneShot("PlayerGun3Start");
                aM.PlaySound("PlayerGun3Loop");
            }else if (!pUpMan.mGunThree)
            {
                aM.StopSound("PlayerGun3Loop");

            }
           
        }
        if (Input.GetButtonUp("Jump"))
        {
            StopCoroutine(rapidFireCoroutine);
            if (pUpMan.mGunThree)
            {
                aM.StopSound("PlayerGun3Loop");
                aM.PlayOneShot("PlayerGun3End");
                
            }
            else if (!pUpMan.mGunThree)
            {
                aM.StopSound("PlayerGun3Loop");

            }
            animatorMuzzleFlash.SetFloat("Muzzle", 0.4f);
            animatorMuzzleFlash2.SetFloat("Muzzle", 0.4f);
            animatorMuzzleFlash3.SetFloat("Muzzle", 0.4f);
        }


    }

I was talking about this code at the end of my last post. When I push the button the block starts to fire rapidFireCoroutine. If the pUpMan.mGunThree becomes true while the “Jump”
button was still down, the sounds do not fire until the button is released and pressed again.

I added debug.log inside both if statements and they get fired so I think the if statements are getting called.
And changing to GetButton was the first thing I did but it messes the rapidFireCoroutine and starts to instantiate a million bulets so I would probably need to change different parts of the code. That’s why I didn’t try that any further.

I don’t want to take more of your time since I tinkered kind of a solution with your pointers as I wrote in my last post. I am asking these questions because first I am trying to learn and second these posts are helping me afterward when I have kind of the same but different problems…=)

I am going to mark your second post as the solution since It has two different way of thinking pointed out.Thanks and cheers…=)

Which makes sense because the two if-blocks get executed only in the one single frame when the button was pressed down and released respectively. If the player keeps pressing the button, the inner if-statements do not get checked again because the outer if-conditions get evaluated to false.

Here is a table for you:

FRAME PLAYER ACTION UNITY METHODS RETURNING TRUE
0 presses button down GetButtonDown, GetKeyDown
1 keeps pressing button GetButton, GetKey
2 keeps pressing button GetButton, GetKey
3 keeps pressing button GetButton, GetKey
… keeps pressing button GetButton, GetKey
9000 releases button GetButtonUp, GetKeyUp

Don’t worry if this does not make sense. I think it is a good idea if you leave this problem alone for a while and proceed with your project. When spending “too much time” with a problem, we tend to get stuck in a rut. If you revise your current solution/code at a later juncture after you solved other problems, it might well be that you will immediately spot the issue.

1 Like

Well I am about to share our first level in the forum…Hopefully today…so we will see if my tinkering to this problem or to the other problems I asked in here works well…=)

Thanks again Nina…=)

Cheers…=)

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.