GameMaker How to Efficiently Check if Player is Moving Diagonally

  • Thread starter captiongoosebut
  • Start date
C

captiongoosebut

Guest
I want to set the variable "spd" to "spd * 0.707" while the player is moving diagonally to normalize diagonal movement speed.

I could make a bunch of if statements saying something like if key_a and key_w diagonal == true, etc, but that would be (I think) very inefficient, and have problems as well. If anyone has done this before and has recommendation please let me know.

Here is my movement code:

Code:
key_up = keyboard_check(ord("W"));
key_left = keyboard_check(ord("A"));
key_down = keyboard_check(ord("S"));
key_right = keyboard_check(ord("D"));

var hMove = key_right - key_left;
var vMove = key_up - key_down;

hsp = hMove * spd;
vsp = vMove * spd;
 

NicoFIDI

Member
Code:
key_up = keyboard_check(ord("W"));
key_left = keyboard_check(ord("A"));
key_down = keyboard_check(ord("S"));
key_right = keyboard_check(ord("D"));

var hAxis = key_right - key_left;
var vAxis = key_up - key_down;
var dir = point_direction(0,0,hAxis,vAxis);

var hMove = dcos(dir);
var vMove =-dsin(dir);

hsp = hMove * spd;
vsp = vMove * spd;
 
C

captiongoosebut

Guest
Code:
key_up = keyboard_check(ord("W"));
key_left = keyboard_check(ord("A"));
key_down = keyboard_check(ord("S"));
key_right = keyboard_check(ord("D"));

var hAxis = key_right - key_left;
var vAxis = key_up - key_down;
var dir = point_direction(0,0,hAxis,vAxis);

var hMove = dcos(dir);
var vMove =-dsin(dir);

hsp = hMove * spd;
vsp = vMove * spd;
Could I get an explanation of what this does and how I should use it? I just don't understand the code sorry.
 
E

Ephemeral

Guest
Basically, you take your move speed and your input direction separately, and then use the handy lengthdir functions to convert those values into the correct hsp and vsp, like so. This works for n-directional movement seamlessly, because there are no special cases to handle.

Code:
move = 4;

horizontal_input = key_right - key_left;
vertical_input = key_down - key_up;

input_direction = point_direction(0, 0, horizontal_input, vertical_input);

hsp = lengthdir_x(move, input_direction);
vsp = lengthdir_y(move, input_direction);
 

NightFrost

Member
To expand a bit more, both code samples above use trigonometry to arrive to the solution. Your speed is the hypotenuse length and direction is the angle. Trig is then used to solve horizontal and vertical side lengths, which become your movement deltas. The lengthdir commands are just wrappers for the same math so you can do code without having to think about triangles and sin and cos.
 
W

Woochi

Guest
K.I.S.S

Code:
if (x != xprevious && y != yprevious) {
   // You are moving diagonally, change speed
}
No: this would also change speed if you get moved by something else, and not limited to inherent movement, whereas use of hsp and vsp manipulates just those factors in the movement formula.
 
Using trig is a good solution. But if you want to take the more understandable, simple route...

Checking if you're moving diagonally just means you are moving in the x and y direction at the same time. So just check if both of them are not 0.
Code:
if (hMove != 0 and vMove != 0) {
   hsp = hMove * spd * 0.707;
   vsp = vMove * spd * 0.707;
} else {
   hsp = hMove * spd;
   vsp = vMove * spd;
}
or using a local var
Code:
var tempSpd = spd;

if (hMove != 0 and vMove != 0) {
   tempSpd *= 0.707;
}

hsp = hMove * tempSpd;
vsp = vMove * tempSpd;
 
C

captiongoosebut

Guest
Using trig is a good solution. But if you want to take the more understandable, simple route...

Checking if you're moving diagonally just means you are moving in the x and y direction at the same time. So just check if both of them are not 0.
Code:
if (hMove != 0 and vMove != 0) {
   hsp = hMove * spd * 0.707;
   vsp = vMove * spd * 0.707;
} else {
   hsp = hMove * spd;
   vsp = vMove * spd;
}
or using a local var
Code:
var tempSpd = spd;

if (hMove != 0 and vMove != 0) {
   tempSpd *= 0.707;
}

hsp = hMove * tempSpd;
vsp = vMove * tempSpd;
These solutions are both great, and seem to work, but with 1 problem. When the player is moving diagonally for some reason he looks really shaky. The player is slowed down properly, but is vibrating when moving diagonally, which seems very odd to me.
 
These solutions are both great, and seem to work, but with 1 problem. When the player is moving diagonally for some reason he looks really shaky. The player is slowed down properly, but is vibrating when moving diagonally, which seems very odd to me.
Which way is he shaking? Like up and down or left and right? I don't really know why that would be happening. How are you incrementing the x and y position?
 
C

captiongoosebut

Guest
Which way is he shaking? Like up and down or left and right? I don't really know why that would be happening. How are you incrementing the x and y position?
It's just a really subtle vibration. Honestly the player just looks blurry when moving diagonally.
 

Perseus

Not Medusa
Forum Staff
Moderator
These solutions are both great, and seem to work, but with 1 problem. When the player is moving diagonally for some reason he looks really shaky. The player is slowed down properly, but is vibrating when moving diagonally, which seems very odd to me.
That is most likely due to fractional coordinates. It is actually a hardware limit on account of how there's practically nothing like "fraction of a pixel," and GameMaker tends to handle rounding off of drawing coordinates inconsistently which results in the shaking. Try manually drawing the player sprite at rounded coordinates (round them via floor or ceil - though, round off only the position where the sprite gets drawn, not the actual coordinates as that might mess up the movement).
Code:
// DRAW
draw_sprite_ext(sprite_index, image_index, floor(x), floor(y), image_xscale, image_yscale, image_angle, image_blend, image_alpha);
 

NicoFIDI

Member
this might not work for you but i fix the blurr of the player unchecking (interpolate colours) on the game configuration settings
and using this line of code on the step
Code:
if (xprevious == x) x = round(x);
if (yprevious == y) y = round(y);
this way you can move by decimals while you keep moveing, and it fixes when you dont move'

[EDIT] But the comment avobe it's way better XD
 
Top