• 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!

Diagonal movement with analog stick

Rook

Member
I have a movement script which adjusts diagonal movement. I also can use it with a controller, but the diagonal movement is slightly slower with the thumbstick than when using binary keys. Any idea on how to fix it?

Code:
if (abs(gamepad_axis_value(0,gp_axislh)) > 0.2)
{
    keyLeft = abs(min(gamepad_axis_value(0,gp_axislh),0));
    keyRight = max(gamepad_axis_value(0,gp_axislh),0);
}

if (abs(gamepad_axis_value(0,gp_axislv)) > 0.2)
{
    keyDown = abs(max(gamepad_axis_value(0,gp_axislv),0));
    keyUp = abs(min(gamepad_axis_value(0,gp_axislv),0));
}

var moveX = keyRight - keyLeft;
var moveY = keyDown - keyUp;
mdirection = point_direction(0, 0, moveX, moveY);
hSpeed = lengthdir_x(speedMove , mdirection) * abs(moveX);
vSpeed = lengthdir_y(speedMove , mdirection) * abs(moveY);


if (place_meeting (x+hSpeed,y,obj_wall))
{
    while (!place_meeting(x+sign(hSpeed),y,obj_wall))
    {
        x = x + sign(hSpeed);
    }
    hSpeed = 0
}
x += hSpeed;

if (place_meeting (x,y+vSpeed,obj_wall))
{
    while (!place_meeting(x,y+sign(vSpeed),obj_wall))
    {
        y = y + sign(vSpeed);
    }
    vSpeed = 0
}
y += vSpeed;
 

Roleybob

Member
This:
GML:
if (abs(gamepad_axis_value(0,gp_axislh)) > 0.2)
{
    keyLeft = abs(min(gamepad_axis_value(0,gp_axislh),0));
    keyRight = max(gamepad_axis_value(0,gp_axislh),0);
}

if (abs(gamepad_axis_value(0,gp_axislv)) > 0.2)
{
    keyDown = abs(max(gamepad_axis_value(0,gp_axislv),0));
    keyUp = abs(min(gamepad_axis_value(0,gp_axislv),0));
}
Isn't very nice code

As you are not varying the movement speed based on how far the stick is pressed, to find the direction that the stick is being pressed in you can just use:
GML:
var moveX = gamepad_axis_value(0, gp_axislh);
var moveY = gamepad_axis_value(0, gp_axislv);
if abs(moveX < 0.2)
    moveX = 0;
if abs(moveY < 0.2)
    moveY = 0;

mdirection = point_direction(0, 0, moveX, moveY);
hSpeed = lengthdir_x(speedMove, mdirection);
vSpeed = lengthdir_y(speedMove, mdirection);

As for the speed of movement, what is your normal key movement code? Maybe you are moving horizontally at speedMove and also vertically at speedMove when the player is using the keyboard? That would make the character move at about 1.4 * speedMove

EDIT: have added the checks to ensure that moveX and moveY have to be over 0.2 before registering
 
Last edited:

Rook

Member
This:
GML:
if (abs(gamepad_axis_value(0,gp_axislh)) > 0.2)
{
    keyLeft = abs(min(gamepad_axis_value(0,gp_axislh),0));
    keyRight = max(gamepad_axis_value(0,gp_axislh),0);
}

if (abs(gamepad_axis_value(0,gp_axislv)) > 0.2)
{
    keyDown = abs(max(gamepad_axis_value(0,gp_axislv),0));
    keyUp = abs(min(gamepad_axis_value(0,gp_axislv),0));
}
Isn't very nice code

As you are not varying the movement speed based on how far the stick is pressed, to find the direction that the stick is being pressed in you can just use:
GML:
var moveX = gamepad_axis_value(0, gp_axislh);
var moveY = gamepad_axis_value(0, gp_axislv);
if abs(moveX < 0.2)
    moveX = 0;
if abs(moveY < 0.2)
    moveY = 0;

mdirection = point_direction(0, 0, moveX, moveY);
hSpeed = lengthdir_x(speedMove, mdirection);
vSpeed = lengthdir_y(speedMove, mdirection);

As for the speed of movement, what is your normal key movement code? Maybe you are moving horizontally at speedMove and also vertically at speedMove when the player is using the keyboard? That would make the character move at about 1.4 * speedMove

EDIT: have added the checks to ensure that moveX and moveY have to be over 0.2 before registering
The inputs are called first

GML:
keyLeft = keyboard_check(ord("A"));
keyRight = keyboard_check(ord("D"));
keyUp = keyboard_check(ord("W"));
keyDown = keyboard_check(ord("S"));
Then the moveX and Y vars apply them

GML:
var moveX = keyRight - keyLeft;
var moveY = keyDown - keyUp;
 

Roleybob

Member
And then do you use
GML:
mdirection = point_direction(0, 0, moveX, moveY);
hSpeed = lengthdir_x(speedMove , mdirection) * abs(moveX);
vSpeed = lengthdir_y(speedMove , mdirection) * abs(moveY);
as with the gamepad?

Do you definitely want 360 degree movement with the gamepad but 8-directional movement with the keyboard?

if this part of your code:

Code:
var moveX = keyRight - keyLeft;
var moveY = keyDown - keyUp;
mdirection = point_direction(0, 0, moveX, moveY);
hSpeed = lengthdir_x(speedMove , mdirection) * abs(moveX);
vSpeed = lengthdir_y(speedMove , mdirection) * abs(moveY);


if (place_meeting (x+hSpeed,y,obj_wall))
{
    while (!place_meeting(x+sign(hSpeed),y,obj_wall))
    {
        x = x + sign(hSpeed);
    }
    hSpeed = 0
}
x += hSpeed;

if (place_meeting (x,y+vSpeed,obj_wall))
{
    while (!place_meeting(x,y+sign(vSpeed),obj_wall))
    {
        y = y + sign(vSpeed);
    }
    vSpeed = 0
}
y += vSpeed;
Is the same for gamepad as it is for keys then I don't see how they could be producing different speeds. However, the gamepad code allows for 360 degree movement while the keys don't so maybe you are just not pushing exactly diagonally with the gamepad and the difference in speed is illusory
 
Last edited:

Rook

Member
And then do you use
GML:
mdirection = point_direction(0, 0, moveX, moveY);
hSpeed = lengthdir_x(speedMove , mdirection) * abs(moveX);
vSpeed = lengthdir_y(speedMove , mdirection) * abs(moveY);
as with the gamepad?

Do you definitely want 360 degree movement with the gamepad but 8-directional movement with the keyboard?

if this part of your code:

Code:
var moveX = keyRight - keyLeft;
var moveY = keyDown - keyUp;
mdirection = point_direction(0, 0, moveX, moveY);
hSpeed = lengthdir_x(speedMove , mdirection) * abs(moveX);
vSpeed = lengthdir_y(speedMove , mdirection) * abs(moveY);


if (place_meeting (x+hSpeed,y,obj_wall))
{
    while (!place_meeting(x+sign(hSpeed),y,obj_wall))
    {
        x = x + sign(hSpeed);
    }
    hSpeed = 0
}
x += hSpeed;

if (place_meeting (x,y+vSpeed,obj_wall))
{
    while (!place_meeting(x,y+sign(vSpeed),obj_wall))
    {
        y = y + sign(vSpeed);
    }
    vSpeed = 0
}
y += vSpeed;
Is the same for gamepad as it is for keys then I don't see how they could be producing different speeds. However, the gamepad code allows for 360 degree movement while the keys don't so maybe you are just not pushing exactly diagonally with the gamepad and the difference in speed is illusory
It is definitely slower on the thumb stick, I think my only option is to change movement based on whether the thumbstick is being used or not.
 

Roleybob

Member
Ah, I think I see why -

You are multiplying hSpeed and vSpeed by abs(moveX) and abs(moveY) which have values less than 1.

I assume you are doing this as you don't want the character to move when the player is not pushing in a direction but a side effect is that it is slowing your movement down.

You need to do your check a different way and get rid of those multiplyers. Try this:

GML:
var moveX = gamepad_axis_value(0, gp_axislh);
var moveY = gamepad_axis_value(0, gp_axislv);
if abs(moveX < 0.2)
    moveX = 0;
if abs(moveY < 0.2)
    moveY = 0;

if ((moveX == 0) && (moveY == 0))
    exit;

mdirection = point_direction(0, 0, moveX, moveY);
hSpeed = lengthdir_x(speedMove, mdirection);
vSpeed = lengthdir_y(speedMove, mdirection);

if (place_meeting (x+hSpeed,y,obj_wall))
{
    while (!place_meeting(x+sign(hSpeed),y,obj_wall))
    {
        x = x + sign(hSpeed);
    }
    hSpeed = 0
}
x += hSpeed;

if (place_meeting (x,y+vSpeed,obj_wall))
{
    while (!place_meeting(x,y+sign(vSpeed),obj_wall))
    {
        y = y + sign(vSpeed);
    }
    vSpeed = 0
}
y += vSpeed;
 

Rook

Member
Ah, I think I see why -

You are multiplying hSpeed and vSpeed by abs(moveX) and abs(moveY) which have values less than 1.

I assume you are doing this as you don't want the character to move when the player is not pushing in a direction but a side effect is that it is slowing your movement down.

You need to do your check a different way and get rid of those multiplyers. Try this:

GML:
var moveX = gamepad_axis_value(0, gp_axislh);
var moveY = gamepad_axis_value(0, gp_axislv);
if abs(moveX < 0.2)
    moveX = 0;
if abs(moveY < 0.2)
    moveY = 0;

if ((moveX == 0) && (moveY == 0))
    exit;

mdirection = point_direction(0, 0, moveX, moveY);
hSpeed = lengthdir_x(speedMove, mdirection);
vSpeed = lengthdir_y(speedMove, mdirection);

if (place_meeting (x+hSpeed,y,obj_wall))
{
    while (!place_meeting(x+sign(hSpeed),y,obj_wall))
    {
        x = x + sign(hSpeed);
    }
    hSpeed = 0
}
x += hSpeed;

if (place_meeting (x,y+vSpeed,obj_wall))
{
    while (!place_meeting(x,y+sign(vSpeed),obj_wall))
    {
        y = y + sign(vSpeed);
    }
    vSpeed = 0
}
y += vSpeed;
It works! Kind of... Right now it only moves right and down, but I tested it against one using the binary system from before and they moved at the same speed.
 

Roleybob

Member
Sorry, I have only recently come back to GM so I am out of practice (and only ever had limited knowledge anyway) but I'm glad that we're making progress...

I'm happy to try to give some more help but if you get any other help in the meantime then I won't be upset if you take their advice over mine! Probably the best advice I could give on this site is - if you are lucky enough to get help from Nocturne, Yal, FrostyCat, TheouAegis, or many others (sorry for the many omissions) then you should spend time trying to understand what they are telling you and why they are telling it to you.

I'm rambling now and clearly in no state to look at or write code so I'm signing out, will try to have another look over the weekend though
 

dudaxan

Member
Hey! How are you doing?

Your mistake is at these lines:
if abs(moveX < 0.2)
moveX = 0;
if abs(moveY < 0.2)
moveY = 0;

It should be:
if abs(moveX) < 0.2 moveX = 0;
if abs(moveY) < 0.2 moveY = 0;

For your original code, you are running something like abs(true/false) and that will result true (1) when it is true and false (0) when it is false.
 

Rook

Member
Hey! How are you doing?

Your mistake is at these lines:
if abs(moveX < 0.2)
moveX = 0;
if abs(moveY < 0.2)
moveY = 0;

It should be:
if abs(moveX) < 0.2 moveX = 0;
if abs(moveY) < 0.2 moveY = 0;

For your original code, you are running something like abs(true/false) and that will result true (1) when it is true and false (0) when it is false.
All working as intended now, thanks for your help and patience!
 

Rook

Member
Hi again, unfortunately it also removed the ability to gradually change speed with the stick depending on how far you push it, which was its poor implementation before which caused the problem in the first place. Probably should of paid attention.
 

CMAllen

Member
In your original code, you had these two lines:
GML:
hSpeed = lengthdir_x(speedMove , mdirection) * abs(moveX);
vSpeed = lengthdir_y(speedMove , mdirection) * abs(moveY);
That is where you used the gamepad_axis_value position to determine the speed of movement. You just applied it in the wrong place:
GML:
hSpeed = lengthdir_x(speedMove * abs(moveX), mdirection);
vSpeed = lengthdir_y(speedMove * abs(moveY), mdirection);
To be clear a gamepad_axis_value has a range of between -1.0 and 1.0. The question is how *much* you want the gamepad axis to impact movement speed and how quickly you want it to scale up to maximum value.

GML:
var axisMult = 1.5;
var axisMax = 1.0;
var moveX = gamepad_axis_value(0, gp_axislh)*axisMult;
var moveY = gamepad_axis_value(0, gp_axislv)*axisMult;

if abs(moveX)  < 0.2
    moveX = 0;
if abs(moveX)  > axisMax
    moveX = axisMax * sign(moveX);

if abs(moveY) < 0.2
    moveY = 0;
if abs(moveY)  > axisMax
    moveY = axisMax * sign(moveY);
This will mutiply the axis amount by whatever value you think is appropriate, while clamping the maximum value of your axis to, again, whatever speed multiplier you think results in the best feel to gamepad movement. In this case, the axis values are increased by 50%, while the maximum contribution of the gamepad axis is still clamped to 1.0, but you can easily alter the first to variables two experiment.
 
Last edited:

Rook

Member
In your original code, you had these two lines:
GML:
hSpeed = lengthdir_x(speedMove , mdirection) * abs(moveX);
vSpeed = lengthdir_y(speedMove , mdirection) * abs(moveY);
That is where you used the gamepad_axis_value position to determine the speed of movement. You just applied it in the wrong place:
GML:
hSpeed = lengthdir_x(speedMove * abs(moveX), mdirection);
vSpeed = lengthdir_y(speedMove * abs(moveY), mdirection);
To be clear a gamepad_axis_value has a range of between -1.0 and 1.0. The question is how *much* you want the gamepad axis to impact movement speed and how quickly you want it to scale up to maximum value.

GML:
var axisMult = 1.5;
var axisMax = 1.0;
var moveX = gamepad_axis_value(0, gp_axislh)*axisMult;
var moveY = gamepad_axis_value(0, gp_axislv)*axisMult;

if abs(moveX)  < 0.2
    moveX = 0;
if abs(moveX)  > axisMax
    moveX = axisMax * sign(moveX);

if abs(moveY) < 0.2
    moveY = 0;
if abs(moveY)  > axisMax
    moveY = axisMax * sign(moveY);
This will mutiply the axis amount by whatever value you think is appropriate, while clamping the maximum value of your axis to, again, whatever speed multiplier you think results in the best feel to gamepad movement. In this case, the axis values are increased by 50%, while the maximum contribution of the gamepad axis is still clamped to 1.0, but you can easily alter the first to variables two experiment.
Dude, that's perfect, thanks.
 
Top