1

In my code I am trying to detect whether a key for example 'A' is pressed alone or is pressed with combination. I have different if statements for each. But when I press them together something weird happens. I think the problem is related to Input.Getkey and when I try to use Input.GeyKeyDown it becomes nearly impossible to press them both at the same time. How can I improve my code?

It seems a common problem but I am unable to comprehend it. I want my transform to move to different location when only A is pressed and to another different location when A is pressed in combination with W or S. The result I want is in the image. When I click a&&w then generate a random Vector3 between a range like this:

new Vector3(Random.Range(-2.7f, -0.95f), 0, Random.Range(4.5f, 6f));

Generating random location works perfectly but the only problem is when I try to press combination keys, first this runs

if (Input.GetKeyUp(KeyCode.W))
    {
        activePos = new Vector3(Random.Range(0.95f, -0.95f), 0, Random.Range(4.5f, 6f));

        return activePos;
    }

then this

if (Input.GetKey(KeyCode.A) || (Input.GetKey(KeyCode.Q) && Input.GetKey(KeyCode.A)))
    {
        activePos = new Vector3(Random.Range(-2.7f, -0.95f), 0, Random.Range(2f, 4.5f));

        return activePos;
    }

and this

if (Input.GetKey(KeyCode.W) && Input.GetKey(KeyCode.A))
    {
        activePos = new Vector3(Random.Range(-2.7f, -0.95f), 0, Random.Range(4.5f, 6f));

        return activePos;
    }

Whereas I want only the last one to run. I want only this code to run when w&&a are pressed together

if (Input.GetKey(KeyCode.W) && Input.GetKey(KeyCode.A))
        {
            activePos = new Vector3(Random.Range(-2.7f, -0.95f), 0, Random.Range(4.5f, 6f));

            return activePos;
        }

enter image description here

This is the full method:

public static Vector3 GetTargetPosition()
{
    /*
     * near z = 1 - 2.5, key  = s
     * center z = 2 - 4.5, key  = q
     * far z = 4.5 - 6, key  = w
     * very far possibly outside z = 6 - 7.5
     * left x = (-2.7) to -0.95, key  = a
     * center x = -0.95 to 0.95, key  = q
     * right x = 0.95 to 2.7, key  = d
     */

    if (Input.GetKeyUp(KeyCode.S))
    {
        activePos = new Vector3(Random.Range(0.95f, -0.95f), 0, Random.Range(1f, 2.5f));

        return activePos;
    }
    else if (Input.GetKeyUp(KeyCode.W))
    {
        activePos = new Vector3(Random.Range(0.95f, -0.95f), 0, Random.Range(4.5f, 6f));

        return activePos;
    }
    else if (Input.GetKeyUp(KeyCode.Q))
    {
        activePos = new Vector3(Random.Range(0.95f, -0.95f), 0, Random.Range(2f, 4.5f));

        return activePos;
    }
    else if (Input.GetKey(KeyCode.S) && Input.GetKey(KeyCode.A))
    {
        activePos = new Vector3(Random.Range(-2.7f, -0.95f), 0, Random.Range(1f, 2.5f));

        return activePos;
    }
    else if (Input.GetKey(KeyCode.S) && Input.GetKey(KeyCode.D))
    {
        activePos = new Vector3(Random.Range(0.95f, 2.7f), 0, Random.Range(1f, 2.5f));

        return activePos;
    }
    else if (Input.GetKey(KeyCode.W) && Input.GetKey(KeyCode.A))
    {
        activePos = new Vector3(Random.Range(-2.7f, -0.95f), 0, Random.Range(4.5f, 6f));

        return activePos;
    }
    else if (Input.GetKey(KeyCode.W) && Input.GetKey(KeyCode.D))
    {
        activePos = new Vector3(Random.Range(0.95f, 2.7f), 0, Random.Range(4.5f, 6f));

        return activePos;
    }
    else if (Input.GetKey(KeyCode.A) || (Input.GetKey(KeyCode.Q) && Input.GetKey(KeyCode.A)))
    {
        activePos = new Vector3(Random.Range(-2.7f, -0.95f), 0, Random.Range(2f, 4.5f));

        return activePos;
    }
    else if (Input.GetKey(KeyCode.D) || (Input.GetKey(KeyCode.Q) && Input.GetKey(KeyCode.D)))
    {
        activePos = new Vector3(Random.Range(0.95f, 2.7f), 0, Random.Range(2f, 4.5f));
        return activePos;
    }
    else
    {
        return new Vector3(0, 0, 0);
    }
}
2
  • Note: if/else statements choose the first matching option, not the best matching option. It will always match S before it even has a chance to match S&&A or S&&D. Commented Mar 21, 2018 at 6:22
  • Blurb from close dialog: Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: How to create a minimal reproducible example. Commented Mar 21, 2018 at 6:25

4 Answers 4

3

The problem isn't with

if (Input.GetKey(KeyCode.W) && Input.GetKey(KeyCode.A))

as this is perfectly fine for what you are trying to do.

the problem lies with the fact that you are using a lot of if-else statements.

Your code is being run sequential, meaning from top to bottom. if you hit both the keys A and W it will go through your code and the first match it will find will be

else if (Input.GetKeyUp(KeyCode.W)) { activePos = new Vector3(Random.Range(0.95f, -0.95f), 0, Random.Range(4.5f, 6f));

  return activePos;
}

since you did actually press the W, which will perform the code inside this if statement and break out of all other cases. Never reaching

 else if (Input.GetKey(KeyCode.W) && Input.GetKey(KeyCode.A))
{
    activePos = new Vector3(Random.Range(-2.7f, -0.95f), 0, Random.Range(4.5f, 6f));

    return activePos;
}

There are multiple ways you can can go around this, each having their own pros and cons.

What i would personally probably do is nest your if statements. This will mean that you will first check if key A is pressed, and inside that if statement you can do another check to see if W is also pressed, for example:

if(Input.GetKey(KeyCode.A))
{
    //some logic goes here for when A is pressed
    if(Input.GetKey(KeyCode.W))
    {
       //some logic for when both A and W are pressed
    }
}

the pro of this is that you can do both the A and W check in the same if statement.

or you could do something like this:

 if(Input.GetKey(KeyCode.W) && Input.GetKey(KeyCode.A))
 {
     //logic for both A And W pressed
 }

 if(Input.GetKey(KeyCode.W) && !Input.GetKey(KeyCode.A))
 {
     //by checking if A is NOT pressed you will prevent this code from 
     //running if you press both A and W
     //Logic for just W pressed
 }

in short; get rid of the entire if-else structure and just stick with the if, if for some reason you really want to stick with the if-else structure reversing the order in which you check everything will also do (e.g check for the double key presses first, and the single key presses after, since you break out of the if-else after the first positive hit) but i wouldn't recommend this approach.

also you don't have to return the active pos. just setting it with = new Vector3 is all you need to do!

Apologies if the formatting of the post is a bit messy, typing this quick from mobile!

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for this valuable answer. You helped me a lot.
1

I assume this function will be called in Update() function, which is executed on every frame.

You don't have to use logic and A && B for the case when two keys are pressed at the same time, just define A and B case separately, and when both are called, the changes are applied sequentially, but very quickly, so quick that no one can detect such sequence, which meet your requirement.

if (Input.GetKeyUp(KeyCode.A)) {...}
if (Input.GetKeyUp(KeyCode.B)) {...}
// if (Input.GetKeyUp(KeyCode.A) && Input.GetKeyUp(KeyCode.A)) {...} //Avoid this!

Update:

if (Input.GetKeyUp(KeyCode.A)) {
     activePos += ... //Let activePos to be class level variable, no need to return;
}

Comments

0

You can try setting a value with each key press, so when you press the a key it sets bool a = true. Then later you can check with if (a && d) or something similar.

Comments

0

Try this one:

if ((Input.GetKey(KeyCode.S) && Input.GetKeyUp(KeyCode.Q)) || (Input.GetKey(KeyCode.Q) && Input.GetKeyUp(KeyCode.S)))
{
    DoCode();
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.