SOLVED Moving 2 characters at once with different inputs

may0naze

Member
Hello,

I found an issue in my game in which 2 characters have to be controlled, one with WASD and another with arrow keys. The movement is timer-based and accepts a single input at a time. If during a particular state (say, objectstate.inputs), a movement option is inputted, the relevant character changes state (objectstate.move), moves and a timer begins counting down, and when that timer reaches -1, the object state changes again (objectstate.locked) and no more inputs are accepted.

When I input something for both characters simultaneously on the same frame (say, W and right arrow) the game seemingly picks one input at random. I doubt it has to do with keyboard ghosting or anything like that since it only happens when I input the keys on the same frame and the decision as to which one to go with seems to be random as I said, also I tried different key layouts and it still happens.

The code checks for one of the 4 keys for each object and executes a switch statement (the key definitions are different for each character object):

GML:
if(keyboard_check_pressed(keyUp||keyDown||keyLeft||keyRight)){
    if(keyboard_key == keyUp||keyDown||keyLeft||keyRight)
        _press = keyboard_key;
    else
        _press = 0;
    switch(_press){
        case keyUp:
            movementY = -movement;
            validInput = true;
        break;
        case keyDown:
            movementY = movement;
            validInput = true;
        break;
        case keyLeft:
            movementX = -movement;
            validInput = true;
        break;
        case keyRight:
            movementX = movement;
            validInput = true;
        break;
    }
}
Formerly I was using keyboard_check instead of keyboard_check_pressed and keyboard_lastkey instead of keyboard_key, though changing it didn't seem to matter. I assume these variables are bad to use since they only store 1 input at a time, whereas I need 2 to be stored at once if I'm inputting the movement simultaneously.

Also I'm using a Draw GUI event and I've confirmed that it simply doesn't pick up one of the inputs when inputted simultaneously.

What should I do?
 
If I had to take a stab at a guess, I would say think of keyboard_key as a global variable. It can only store a single key per frame. So your instances are fighting over that value.
 

FrostyCat

Redemption Seeker
See: How NOT to use && and || (#6)
WRONG:
Code:
keyboard_check(vk_up && vk_down)
RIGHT:
Code:
keyboard_check(vk_up) && keyboard_check(vk_down)
WRONG:
Code:
keyboard_check_pressed(vk_left || ord("A"))
RIGHT:
Code:
keyboard_check_pressed(vk_left) || keyboard_check_pressed(ord("A"))
  • DO NOT translate English sentences word-for-word into GML symbols.
  • If either side of an && or || operator is not meant to be treated as a Boolean value (true/false), the code is wrong.
 

may0naze

Member
I feel I should justify myself by saying that I only made the code this way because what I did wasn't working. Previously it looked like this:

GML:
if(keyboard_check(vk_anykey)){
    switch(keyboard_lastkey){
    //The rest is the same.
    }
}
I see your corrections making more sense, but what I've written also works besides the same frame input thing. I'll be happy to tidy it up once that's resolved.

Edit: I made the corrections. It didn't help the issue at hand, but it was good to know about regardless. Thanks.
 
Last edited:

may0naze

Member
If I had to take a stab at a guess, I would say think of keyboard_key as a global variable. It can only store a single key per frame. So your instances are fighting over that value.
I already acknowledged this near the end of my post, I'm struggling to find alternative methods.
 
I already acknowledged this near the end of my post, I'm struggling to find alternative methods.
Doh! I was so focused on the code I missed that part. This doesn't look as elegant, but it should get the job done:
GML:
 _press=0
if keyboard_check_pressed(keyup) _press = keyup
if keyboard_check_pressed(keyDown) _press = keyDown
if keyboard_check_pressed(keyLeft) _press = keyLeft
if keyboard_check_pressed(keyRight) _press = keyRight
 

may0naze

Member
Doh! I was so focused on the code I missed that part. This doesn't look as elegant, but it should get the job done:
GML:
 _press=0
if keyboard_check_pressed(keyup) _press = keyup
if keyboard_check_pressed(keyDown) _press = keyDown
if keyboard_check_pressed(keyLeft) _press = keyLeft
if keyboard_check_pressed(keyRight) _press = keyRight
This actually seems to have done the trick. Thank you very, very much.
I was reluctant to use such code because I keep hearing about how if statements are inefficient and slow, how true is that assessment? Does it apply to something as simple as this code?
 
This actually seems to have done the trick. Thank you very, very much.
I was reluctant to use such code because I keep hearing about how if statements are inefficient and slow, how true is that assessment? Does it apply to something as simple as this code?
Any conditional statement (switch statements included) are supposedly slower than "branchless programming" Branchless Programming (stephanosterburg.com) , but modern compilers are also supposedly pretty good at rearranging the code to optimize CPU instructions. Conditional statements aside, technically my code also has to pay the cost of running the function keyboard_check_pressed 4 times per frame per calling object. You could go a bit further and use else ifs to reduce the number of checks if a key is detected, but then it's still doing 4 checks for every frame that a key is not pressed. So then you could go as far as putting those being a keyboard_check_pressed(vk_anykey), but now you pay an extra check every time there is a key press. But in the end, if optimizing this is saving you .00001% of processing power, it's better to fight your optimization battles elsewhere. Remember, "perfectionism is the enemy of productivity."
 
Top