• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

[SOLVED] Math: limit speed on 'diagonal' movement

Hello all,

Straight up, I know this topic has been done, and done again, but perhaps my take on it is different, perhaps not. I have tried some different things, and have one or two ideas (which may or may not work), but I'd like to see a beautiful or elegant way. But ultimately, Any help greatly appreciated.

I'm moving an object forwards, backwards, sideways(left & right), in relation to the object's pointing direction--(for example's sake, the mouse). I am not using any built-in variables, (and do not wish to).

All works appropriately, except when both a forward|backward key is pressed together with a left|right key.
What happens is the object moves faster than spd == 2, because obviously the x +=, and y-= code is run twice.


How can I write or re-arrange the code to limit the final adjustments to x and y, to spd?


Code:
// where spd == 2
// where radians is a degree value of the direction to point/move in, converted to radians

// FORWARD KEY PRESS
xx = cos(radians) * spd;
yy = sin(radians) * spd;
x += xx;
y -= yy;

// BACKWARD KEY PRESS
xx = cos(radians) * spd;
yy = sin(radians) * spd;
x -= xx;
y += yy;

// SIDEWAYS LEFT KEY PRESS
xx = cos(radians) * spd;
yy = sin(radians) * spd;
x -= xx;
y += yy;

// SIDEWAYS RIGHT KEY PRESS
xx = cos(radians) * spd;
yy = sin(radians) * spd;
x -= xx;
y += yy;
 
Last edited:

obscene

Member
Redo your movement code like this...

x += lengthdir_x(spd,direction);
y += lengthdir_y(spd,direction);

How you get your direction depends on the rest of your code (inputs) but its any value from 0 to 360.
 
H

HammerOn

Guest
You can convert the movement direction in an angle and add it to the pointing direction.
If forwards, backwards, sideways are true or false (1, 0). Something like "point_direction(0, 0, sideway_right-sideway_left, backward-forward)".
This way, you only need
Code:
xx = cos(radians + directionRadians) * spd;
yy = -sin(radians + directionRadians) * spd;
x += xx;
y += yy;
 
obscene and HammerOn, won't that code still get run twice? HaymanMarc,I saw that post earlier--do you mean to say I should just multiply (*=) spd by the magic number?
 
T

TDSrock

Guest
The lengthdir functions are EXACTLY what you want to use here. They utilize the angles just as you were calcing it out above. it just handles it accurately inside the function itself.

If you want you can just do it like this:
Code:
hsp = lengthdir_x(spd,dir);
vsp = lengthdir_y(spd,dir);
x+=hsp;
y+=vsp;
This is how I am handeling the angle based movement in a bubble shooter game I am helping a friend on building.

Then simply have the direction keys be bound to an angle somewhere else in your code.
Code:
key_up = /*whatever the key input thing is here*/;

if(key_up){
   dir = 150;
}
add more keys with else if's
 
I'm sorry TDSrock, I'm not following how this would differ... wouldn't the x+=hsp and y+=vsp still get run twice when I pressed two keys at once??
 

Roderick

Member
Redo your movement code like this...

x += lengthdir_x(spd,direction);
y += lengthdir_y(spd,direction);

How you get your direction depends on the rest of your code (inputs) but its any value from 0 to 360.
This actually solves a problem that I was going to be working on later today, trying to optimize the trig formulas for a similar task. Thanks!

I'm sorry TDSrock, I'm not following how this would differ... wouldn't the x+=hsp and y+=vsp still get run twice when I pressed two keys at once??
Not if your code is written properly.
 
T

TDSrock

Guest
I'm sorry TDSrock, I'm not following how this would differ... wouldn't the x+=hsp and y+=vsp still get run twice when I pressed two keys at once??
The whole point of doing it that way is that at the bottom of your code you state the lines x+= and y+= only ONCE.

I don't want to just give you the answer here. I want you to code it yourself. I've given you all you need to know.
 
Last edited by a moderator:
I'd just like to point out that I never come here asking for help lightly--only when I'm close to 'breaking point'. I've spent four hours every day, for three days on this. I even spent time writing my own "lengthdir" function, to further my understanding--just saying. I do appreciate that people take time though, and I get the "don't wanna post the whole complete answer", thing.

Anyway, I have re-written my code, trying to go by all the posts above. Got problems;
If I only use one "dir", I can not travel in two directions at once. if I use two directions, dir + dir2 (like below) it's all wrong. Also, I still have issues with the double speed---but I think I can do something like this:

Code:
// haven't included this yet
hsp = median(-max_speed, h_speed, max_speed);
vsp = median(-max_speed, v_speed, max_speed);

Code:
// currently using this, results are close, but worse than my original attempt
if keyboard_check(ord('W')){dir  = head_angle;}         // forwards in mouse direction
if keyboard_check(ord('S')){dir  = head_angle - 180;} // backwards opposite to mouse direction
if keyboard_check(ord('A')){dir2 = head_angle + 90;} // strafe left
if keyboard_check(ord('D')){dir2 = head_angle - 90;} // strafe right

hsp = lengthdir_x(spd, dir) + lengthdir_x(spd, dir2);
vsp = lengthdir_y(spd, dir) + lengthdir_y(spd, dir2);
x += hsp;
y += vsp;
 
Last edited:
Hey, check this out:
Code:
    //input
    var _x = 2 * (keyboard_check(ord("W")) - keyboard_check(ord("S")));
    var _y = 2 * (keyboard_check(ord("D")) - keyboard_check(ord("A")));

    //stop diagonal speed boost
    if (_x != 0) and (_y != 0) {
        _x *= sqrt(0.5);
        _y *= sqrt(0.5);
    }

    //get cosine and sine of head_angle
    var _c = dcos(head_angle);
    var _s = dsin(head_angle);

    //move
    x += _c * _x + _s * _y;
    y += _c * _y - _s * _x;
No need for lengthdir or for confusingly using multiple angles. Also, "dcos" and "dsin" take angle argument in degrees. I'm assuming here that "head_angle" determines the direction that is forward.

If you are going to be dealing with accelerations at some point, then you will need to alter the code which stops you from moving diagonally faster than the max speed.
One way to do that would be this:
Code:
    var _sp = sqrt(hsp*hsp + vsp*vsp);
    if (_sp > max_speed) {
        hsp = hsp / _sp * max_speed;
        vsp = vsp / _sp * max_speed;
    }
 
flyingsaucerinvasion, most excellent! Truly marvellous, and many, many thanks! :)

It is both simple, and beautiful. It works flawlessly.

Thank you to all who wrote in to help, it's a great thing, and I look forward to passing on your generosity.

Cheers!
Nathan
 
Top