GML Advice about the keyboard ghosting issue, WASD and Arrow Keys

C

CyberFlash

Guest
Hey,

I had a search and i'm not finding exactly what I'm looking for so decided to make a post. Apologies if it IS in fact duplicated..

I decided to mess around with the sort of idea of those 'twin stick shooters' but without using a controller I was using WASD for movement and Up Down Left Right arrows for shooting...... Now I think its due to keyboard ghosting (I read a bit about it and I don't care too much about the reason its happening but more for solutions right now) but S + D prevents Right Arrow from sending a signal and A + S prevents Down Arrow from sending a signal so there's two times where you can't shoot in a specific direction.

This cannot be a new issue surely.. I'm wondering if there are any suggestions for what keyboard users would use in this situation?

I used a Keyboard Checker and whilst holding S + D I was able to press every other letter so basically every other combination of options for shooting would work but is there a standard for a 'backup button combination' or anything? I used to think WASD was the backup to the arrow keys until I started playing a little on PC (I mainly play Playstation so keyboard info is new to me lol)

I guess I am asking, what is an acceptable replacement for the arrows keys? Or perhaps a 'better' method for shooting.. I could have the player object face the mouse position and have bullets go to there but thats not like the Twin Stick type of thing.. I'm not too bothered if I have to change the concept of course. Its better to change the concept than have people unable to shoot! --- Unless perhaps there's a way to 'fix' this issue? I should have perhaps asked that first :p.

Many Thanks and Happy Holidays!
 
A

Alan Chan

Guest
From the solution I read of another thread, is to use keyboard_check_button() in your step event instead of the designated button events. You can read more about it here https://forum.yoyogames.com/index.php?threads/solutions-to-keyboard-ghosting.20307/, hope it helps!
Ya you are not wrong as well. But you also need the right x and y axis at the same timings. move_towards_point. I will might try to code it for you maybe a bit afterwards when I am free tomorrow.
@CyberFlash , @Zachary_tzy https://docs2.yoyogames.com/source/...d collisions/movement/move_towards_point.html
GameMaker api https://docs2.yoyogames.com/
 
C

CyberFlash

Guest
I might be making a noob mistake but I think I am already doing that, I mean I don't write keyboard_check_button() but I am writing keyboard_check(ord("W")) in my Step Event but I think that's what you mean?

I'm not using 'press <W>' or anything like that, I'm using the Step Event, Perhaps I should paste the code I'm using,



///Movement Controls

//Diagonal Movement Speed Adjustments
if (keyboard_check(ord("W")) && keyboard_check(ord("A"))){ moveSpeed = 4;}
else if (keyboard_check(ord("W")) && keyboard_check(ord("D"))) { moveSpeed = 4;}
else if (keyboard_check(ord("S")) && keyboard_check(ord("A"))) { moveSpeed = 4;}
else if (keyboard_check(ord("S")) && keyboard_check(ord("D"))) { moveSpeed = 4;}
else moveSpeed = 5;

// Up, Left, Down, Right
if (keyboard_check(ord("W")) && !place_meeting(x,y - moveSpeed, objEnemyTwo)) { y-= moveSpeed;}
if (keyboard_check(ord("A")) && !place_meeting(x - moveSpeed,y, objEnemyTwo)) { x-= moveSpeed;}
if (keyboard_check(ord("S")) && !place_meeting(x,y + moveSpeed, objEnemyTwo)) { y+= moveSpeed;}
if (keyboard_check(ord("D")) && !place_meeting(x + moveSpeed,y, objEnemyTwo)) { x+= moveSpeed;}



I'm going to remove the stuff in regards to objEnemyTwo as I was testing something out from a youtube video, but basically with or without the place_meeting objEnemyTwo, this issue happens.


I saw something somewhere about not double posting or something so this is an edit,

I haven't used one before but I am wondering... Would a 'switch' statement thing be usable here? Would that make any difference? I feel the issue lies with the fact that pressing S + D blocks the Right Arrow, So I need better controls?
 
Z

Zachary_tzy

Guest
I might be making a noob mistake but I think I am already doing that, I mean I don't write keyboard_check_button() but I am writing keyboard_check(ord("W")) in my Step Event but I think that's what you mean?

I'm not using 'press <W>' or anything like that, I'm using the Step Event, Perhaps I should paste the code I'm using,



///Movement Controls

//Diagonal Movement Speed Adjustments
if (keyboard_check(ord("W")) && keyboard_check(ord("A"))){ moveSpeed = 4;}
else if (keyboard_check(ord("W")) && keyboard_check(ord("D"))) { moveSpeed = 4;}
else if (keyboard_check(ord("S")) && keyboard_check(ord("A"))) { moveSpeed = 4;}
else if (keyboard_check(ord("S")) && keyboard_check(ord("D"))) { moveSpeed = 4;}
else moveSpeed = 5;

// Up, Left, Down, Right
if (keyboard_check(ord("W")) && !place_meeting(x,y - moveSpeed, objEnemyTwo)) { y-= moveSpeed;}
if (keyboard_check(ord("A")) && !place_meeting(x - moveSpeed,y, objEnemyTwo)) { x-= moveSpeed;}
if (keyboard_check(ord("S")) && !place_meeting(x,y + moveSpeed, objEnemyTwo)) { y+= moveSpeed;}
if (keyboard_check(ord("D")) && !place_meeting(x + moveSpeed,y, objEnemyTwo)) { x+= moveSpeed;}



I'm going to remove the stuff in regards to objEnemyTwo as I was testing something out from a youtube video, but basically with or without the place_meeting objEnemyTwo, this issue happens.


I saw something somewhere about not double posting or something so this is an edit,

I haven't used one before but I am wondering... Would a 'switch' statement thing be usable here? Would that make any difference? I feel the issue lies with the fact that pressing S + D blocks the Right Arrow, So I need better controls?
Hmm I think something might be wrong with your code with so many && and if statements, they probably overlap somewhere and cancel each other out. I was in your boat once! But the conventional and simple way to do a top down movement like that with a stable diagonal speed is like this
Code:
var _x_input = keyboard_check(ord("D")) - keyboard_check(ord("A")) // This will return -1/0/1
var _y_input = keyboard_check(ord("S")) - keyboard_check(ord("W"))

if (_x_input == 1) // Meaning D is pressed and A is not pressed, so go right
{
   // Do your thing here
   x += speed_ // If you want to move by a certain defined speed_
                       // In your example it would be moveSpeed
   OR
   speed_ += acceleration_ // If you want to accelerate at a certain defined pace
}
else if (_x_input == -1) // Meaning A is pressed and D is not pressed, so go left
{
   // Do your thing here
}

if (_y_input == -1) // Same here but for S and W
{
   // Do your thing here
}
else if (_y_input == 1)
{
   // Do your thing here
}

// If you are using acceleration
x += speed_
y += speed_
Something along these lines. Btw you can post your code in between code tags
[*code]Code Here[*/code] without the * inside the square braces. Hope it helps!
 
Last edited by a moderator:
C

CyberFlash

Guest
That looks so much cleaner! I love it! :D I'm going to redo the controls and report back. Thank you for helping :)
 
C

CyberFlash

Guest
Okay so i've updated my movement code, Thank you again for that.

I don't know if I've just been staring at it for too long and it just looks wrong or if its actually happening but I feel like when it goes diagonally, it looks quicker, this is where I'd done the whole:

if (keyboard_check(ord("W")) && keyboard_check(ord("A"))){ moveSpeed = 4;}

and the

else moveSpeed = 5;

so to slow it down if both W and A, W and D, S and A, S and D were pressed, is there anyway of messing with that with the xInput and yInput method?

Also, I still face the issue where pressing S and D is not allowing the Right Arrow key to activate. But I feel like that isn't a game maker issue and using a website keyboardchecker it shows the arrow key as not working when pressing that combination. :/ I feel as though there isn't a 'solution' for my main problem BUT thank you for helping me clean some code, I need to learn the ways of tidy coding properly.
 
Z

Zachary_tzy

Guest
Okay so i've updated my movement code, Thank you again for that.

I don't know if I've just been staring at it for too long and it just looks wrong or if its actually happening but I feel like when it goes diagonally, it looks quicker, this is where I'd done the whole:

if (keyboard_check(ord("W")) && keyboard_check(ord("A"))){ moveSpeed = 4;}

and the

else moveSpeed = 5;

so to slow it down if both W and A, W and D, S and A, S and D were pressed, is there anyway of messing with that with the xInput and yInput method?

Also, I still face the issue where pressing S and D is not allowing the Right Arrow key to activate. But I feel like that isn't a game maker issue and using a website keyboardchecker it shows the arrow key as not working when pressing that combination. :/ I feel as though there isn't a 'solution' for my main problem BUT thank you for helping me clean some code, I need to learn the ways of tidy coding properly.
Your welcome! Hmm from the top of my head now I don't think it would speed up when taking in 2 axis inputs, for example if only D was pressed, it would move 1 pixel per step to the right. If D and W were pressed together, it would move 1 pixel to the right and 1 pixel up per step which is 1 pixel diagonally, so it should not be moving faster with multiple inputs! Unless you have sprites and a room with very small dimensions where you can see very clearly the square, it may seem to move slightly faster. Because a pixel is a square, and when your pixel moves diagonally it travels a slightly further distance, but still only moves 1 pixel per step!

If you really want to mitigate this effect of a square moving diagonally, I think you can have a check at the start of your step event just below the input declarations.
Code:
var moveSpeed = 5
if (_x_input != 0 && _y_input != 0)
{
   moveSpeed = 4
}
The way above works but is not completely accurate because you will have to trial and error the speeds to make them look similar. To get the exact diagonal speed you might want that is similar to the horizontal and vertical speeds, I think you might use a formula like
Code:
var moveSpeed = 5
if (_x_input != 0 && _y_input != 0)
{
   moveSpeed = moveSpeed / sqrt(2) // Which is ~ 3.54
}
This gives you the horizontal speeds you would need to achieve a diagonal distance moved that is similar to your original moveSpeed of 5. I'm not entirely sure but it should work! :)

And I'm sorry it doesn't fix the keyboard ghosting issue for you :( I've personally never had a keyboard ghosting issue and I don't know much about how to fix it. Tidy code comes with practice and learning from others, you will definitely get better at it along the way :) I'm just glad I can help you with something!
 
Last edited by a moderator:
Your welcome! Hmm from the top of my head now I don't think it would speed up when taking in 2 axis inputs, for example if only D was pressed, it would move 1 pixel per step to the right. If D and W were pressed together, it would move 1 pixel to the right and 1 pixel up per step which is 1 pixel diagonally, so it should not be moving faster with multiple inputs! Unless you have sprites and a room with very small dimensions where you can see very clearly the square, it may seem to move slightly faster. Because a pixel is a square, and when your pixel moves diagonally it travels a slightly further distance, but still only moves 1 pixel per step!
Pythagoras was lying to us?! D:<
 
If he were a programmer talking in terms of pixel then yes I guess :D
The answer, to be clear, is to just use decimal positions, even if you only *draw* at round pixel positions. There's no difference between pixels and meters, hahah. Pythagorean theorem applies to both; If you don't normalize your movement vector, you will move significantly faster than you should when traveling diagonally. =)
 
A

Alan Chan

Guest
@CyberFlash
Do you want to make the 8 result aiming that is not as good as the mouse 360° degree turning result?
1. w
2. a
3. s
4. d
5. w + a
6. w + d
7. s + a
8. s + d
OR
Do you want to do the mouse 360° degree PI pie turning to aim your own guns better in the end? But unfortunately I do not really know the PI pie radius math coding of your own characters to like aim everywhere in the end. I believe to do so you need a WASD running legs and the mouse 360° degree spinning upper bodies to like aim and run properly in the end separately with our own animation character movements.
 
Last edited by a moderator:

Paskaler

Member
The arrows + WASD is definetely a problem with gosthing. I recommend to use IJKL for shooting, maybe? Just try and placing your hands on the keyboard in a comfortable fashion and pick the nearest/most easiest to press from those positions for your controls.

As for the diagonal movement, you're going to have to use lengthdir_* functions to maintain a consistent speed regardeless of direction.
These functions require an angle and a length. The length will be your movement speed, so:

Code:
x += lengthdir_x(move_speed, angle);
y += lengthdir_y(move_speed, angle);
Now, for the angle, this can be calculated using the movement inputs:

Code:
var delta_x = right_input - left_input;
var delta_y = down_input - up_input;

var angle = point_direction(0, 0, delta_x, delta_y);
The right_input, left_input, ... should contain the results of the relevant keyboard_check functions, for the right_input, it would be:

Code:
var right_input = keyboard_check(ord("D"));
 
Z

Zachary_tzy

Guest
The answer, to be clear, is to just use decimal positions, even if you only *draw* at round pixel positions. There's no difference between pixels and meters, hahah. Pythagorean theorem applies to both; If you don't normalize your movement vector, you will move significantly faster than you should when traveling diagonally. =)
Yes hence why I gave him the solution to divide his movement speed by the sqrt of 2 to get his desired value which is technically what lengthdir() does but since his horizontal magnitude is the same as his vertical magnitude, I would think there is no need to call lengthdir() and save on some resources. Maybe complex movements which have different x & y magnitude and maybe also factoring in acceleration would require an actual lengthdir() normalization of the resultant vector, but judging from his question, I assumed it is not really necessary in this case.

In some instances you don't have to normalize your movement vector if your movement does not involve actually "travelling", for example a tile based game where you may want to move by tiles, the time it takes to move horizontally and diagonally will be the same assuming you instantaneously move between tiles.

However whether pythagoras theorem applies to his project or not is not for me to decide, and I just wanted to help him with whatever he wishes to accomplish.
 
Last edited by a moderator:
Top