GM:S 1.4 How to normalize diagonal movement without vector?

Discussion in 'Programming' started by rodrick160, Jun 28, 2016.

1. Im using a script that essentially checks whether there is a wall in the direction your about to move in, and if not, moves you there. I'm not looking for anything fancy, just a simple formula using hspeed and vspeed and maybe some other variables that will set it to move the same speed diagonally as it does horizontally and vertically. Thanks!

My movement script:
Code:
///Move Up
if !(collision_rectangle(x+1,y-var_speed,x+31,y,obj_wall,false,true))
vspeed=var_speed*-1
else
vspeed=0

2. flyingsaucerinvasionMember

Joined:
Jun 20, 2016
Posts:
2,168
not totally sure what your question is but hspeed and vspeed can be normalized by dividing by speed. you'll need to use a temporary variable, because if you do hspeed /= speed, it will change the value of speed at the same time, and then vspeed will have a wrong value.

var _speed = speed;
hspeed /= _speed;
vspeed /= _speed;

However, if you are using 8-directional movement. You can stop extra diagonal speed like this:
if (speed > max_speed) { speed = max_speed; }

3. Surgeon_Symbian Curator

Joined:
Jun 22, 2016
Posts:
248
You can think of it like this:
You have two variables, var_speed and direction.
You can represent that movement with trigonometric functions like this:
hspeed=+var_speed*cos(direction), and
vspeed=-var_speed*sin(direction) //Minus here because in Game Maker the Y axis is inverted.
Since sin(a)^2+cos(a)^2=1, the total speed will always be equal to var_speed.

With that said, if you just want simple 45-degree diagonal movement, you just need to set
vspeed=+/-var_speed/sqrt(2), and
hspeed=+/-var_speed/sqrt(2).

If you don't know trigonometry, I suggest you learn it. I know it's been an irreplaceable tool for me ever since I've learned it in school.

-Surgeon_

4. Im assuming 2 is because of pythagoras and assuming var_speed is 1, right? If it were 4 it would be different?

5. hippymanMember

Joined:
Jun 20, 2016
Posts:
565
I've done some pretty extensive testing with this specific issue and I've learned that the magic constant is 0.707

My solution is usually this

Code:
Create Event:
baseSpeed = 4;
xspeed = 0;
yspeed = 0;

Step Event:
var h,v,diag,moveSpd;
h = key_to_axis(vk_right,vk_left);
v = key_to_axis(vk_down,vk_up);
diag = h != 0 && v != 0;

moveSpd = baseSpd;
if (diag) moveSpd *= 0.707;//if moving diagonally multiply the move speed by the "magical constant"

xspeed = h * moveSpd;
yspeed = v * moveSpd;

//Collision code here

x += xspeed;
y += yspeed;

Here's that key_to_axis script
Code:
///key_to_axis(positive,negative);
return keyboard_check(argument0) - keyboard_check(argument1);

6. Surgeon_Symbian Curator

Joined:
Jun 22, 2016
Posts:
248
Here's an illustration: As you can see (because of Pythagoras' theorem), for 45-degree diagonal movement hspeed and vspeed will both always be the maximum speed (var_speed in your case) over square root of 2, then multiplied by +1 or -1, based on direction.

You can also use Game Maker's built in "speed" and "direction" variables and all of this Game Maker will work out behind the scenes.

@hippyman 1/sqrt(2)=sin(45)=cos(45)=0.707106781 so your "magic constant" fits with my more mathematical explanation.

-Surgeon_

hippyman likes this.
7. hippymanMember

Joined:
Jun 20, 2016
Posts:
565
@Surgeon_ That would explain why it works so well! Thanks for actually helping me understand how lol

8. Surgeon_Symbian Curator

Joined:
Jun 22, 2016
Posts:
248
@hippyman Well, you learn something new every day 