GetKeyDown Help

Hello I am using GetKeyDown to start my game. If you keep holding down the button it doesn’t reset and if you die which reloads the scene it will start the game again I am a bit confused?

    public PlayerMovement playerMovement;

    public GameObject anyKeyUI;

    public bool keyActive = false;


    private void Start()
    {
        playerMovement.enabled = false;
    }

    void Update()
    {

            if (Input.GetKeyDown(KeyCode.Space) && keyActive == false)
            {

                keyActive = true;

                // MY UI TEXT
                anyKeyUI.SetActive(false);

                // PLAYER MOVEMENT SCRIPT
                playerMovement.enabled = true;

        }
    }

All it does it makes the playerMovement script active which makes the player move.

Are you setting “keyActive” back to false?

Why is that there anyway? were you using GetKey and forgot to remove it?

What do you mean with that?

GetKeyDown will be true once a key is pressed. It is literally true for one frame, not afterwards, unless the button is released and then pressed again. Besides that you are using the keyActive bool to prevent the if-statement from being entered more than once. So i assume your problem is that it does get entered more than once? That should not be possible, unless you reset the keyActive bool and either press Space or somehow emulate that happening.

While i’m at it; this is not ‘wrong’, but considered bad practice:
You should not compare bools to true or false. If you want keyActive to be true, just write ‘keyActive’. If you want it to be false, just write ‘!keyActive’ (read: not keyActive). Not only does it improve readability and reduces length, but it also prevents some easy to make but hard to notice mistakes. I have read at least half a dozen posts so far where someone used = instead of ==, thus assigned a value there and was wondering why the statement didnt work as expected. And since most people use the short conventions anyways, it’s even quite hard to spot sometimes.

1 Like

I don’t agree with this, when reading someone elses code it’s very easy to miss a ‘!’ in the start of something rather than the ’ == false ’ that yells out at you in most IDEs (I highlight the front ‘!’ too, but it’s still more likely to be missed)

For the record, I have nothing against syntax sugar stuff like this, I have type-C# diabetes from all the condensing I do, haha. :wink:

I am just having a problem where if you hold the space bar down and if you reload the level while still holding it down the space bar it enables playerMovement but ‘GetKeyDown’ should only last one frame no?.

Yes it should only be active for one frame.
Indeed i just tested if a new scene recognizes already pressed buttons as Down again, by using a script where i print a message on GetKeyDown(KeyCode.Space), then load a different scene with the same script on another key press. The message is only printed once, meaning the GetKeyDown(KeyCode.Space) is not triggered again in the next scene. The same is true for loading the same scene again.

So with that said, your bug should be coming from somewhere else. Let’s start with the basics: why do you believe that it is executed twice in the first place? Did you print a message? Is it actually printing again after loading the scene again?
Other than changes done by you, each freshly loaded scene should be in its default state. Just as you designed it.

Edit:
It seems if you are loading a new scene in the same frame GetKeyDown is called, then it is still active in the next scene. I imagine this is the case since it never actually finishes the frame where GetKeyDown would be reset, thus it keeps its state for the first frame of the next scene. Maybe someone can confirm this.

Is there a way to fix it though?

Dont use the same button for changing the scene and doing stuff you dont want to directly happen in the next scene. Why do you even reload the same scene in the first place?
I guess you could remember that you want to load the next scene and do it one Update() cycle later, but i believe there is a general problem design-wise with what you want to do. Maybe try to explain what it is you try to do, so we can find a proper solution.

Its a level bases game if they die the level restarts.

So the control flow would look something like this:
Player needs to press space to start level → player plays → player wins or dies → if player dies he needs to press space to reload the same scene → he is then again supposed to press play when he is ready to start?

I’m just asking because none of this is contained in your code example, so how would we know^^
Personally, i think it’s actually a good thing the user only needs to press space once. After all, if the player decides to restart, why would he need to confirm that he wants to play again?
But back to your problem. I dont think it’s possible to manually reset / disable Input states. Thus, without knowing the structure of your project, the easiest workaround for your situation should be to remember the decision to restart the level and simply execute it the next frame. That should look something like this:

private bool restartLevel = false;
void Update(){
    if(restartLevel){
        // Load the same scene again
    }
    .
    .
    .
    // your actual conditions for restarting the scene
    if(playerDead && spacePressed){
        restartLevel = true;
    }
}

This way you decide to restart the level after the check to actually restart the level. Thus the restart happens one Update() (one frame) later, which should mean that GetKeyDown was reset since the frame it was pressed in ended. I wouldnt exactly consider this a clean solution, but it should work.
I did not test this, but according to the unity life cycle the inputs are processed before Update(), meaning when our Update() with GetKeyDown ends and the next one begins, GetKeyDown should not be true anymore: Unity - Manual: Order of execution for event functions

Its a control restraint from holding a or d and slidding off the edge, since this is a fast past game the control are very fast at moving the player. So what I am trying to do is press any key to continue.

You could check for Input.anyKeyDown (Unity - Scripting API: Input.anyKeyDown) and exclude buttons like a and d (if it’s only a hand full of buttons) by creating a statement like Input.anyKeyDown && !Input.GetKey(KeyCode.A) && .. && ... This would run into the same problems you are experiencing already, but the fix would be the same as well. It may still feel weird if somebody tried to press A or D and nothing happens, so maybe Space is a better solution after all.

So it will not be possible with my current code?

After doing some more testing, i was not able to reproduce my results from above and am majorly confused by now. My suggestion from above also does not work. Neither does ‘skipping’ the first frame after loading a new scene, for some reason.

Anyways, in the process of losing my sanity i had a pretty simple idea to fix your problem. Currently you are doing two things on KeyDown, loading a new scene and also pressing play in that scene. You want it to require two button presses tho. So couldnt you just load the new scene on KeyUp instead? This would mean that the player needs to physically let go of the button, which means it cannot be KeyDown in the next scene to accidentally trigger the play session. The player would then need to press the button again to play.

This worked thanks, I was pretty stupid not to think of this lol. But doesn’t seem to have any (Input.AnyKeyUp), anyway I have fixed this with some simple code.

I would prefer “KeyDown” but not sure how to combat that problem though.