GMS 2 [SOLVED] Getting stuck in corners (top-down view)

Paturicko

Member
I recently started experimenting with motion_add because i find 8 directional movement with motion_add to be more smoother and less rigid. It works great but when I hit a corner at an angle the player gets stuck. This doesn't happen when I use lengthdir instead but i want to keep the smooth movement for keyboard inputs.

Sometimes when I'm stuck i build up speed and teleport to another location or the game stops reading my inputs. Can someone help?

Code:
///input_move()
speed = clamp(speed, 0, maxspd);

if (gamepad_is_connected(0))
{
    //Get Direction
    var axislh = gamepad_axis_value(0,gp_axislh);
    var axislv = gamepad_axis_value(0,gp_axislv);
    dir = point_direction(0, 0, axislh, axislv);

    //Movement && Deadzone
    if (point_distance(0, 0, axislh, axislv) > 0.6)
    {
        obj_player.image_speed = 1;
        motion_add(dir, accel);
        dash_dir = dir;
    }
    else
    {
        obj_player.image_speed = 0;
        obj_player.image_index = 0;
        friction = decel;
    }
}

//Collisions
if (place_meeting(x + hspeed, y, obj_wall))
{
    while (!place_meeting(x + sign(hspeed), y, obj_wall))
    {
        x += sign(hspeed)
    }
    hspeed = 0;
}
if (place_meeting(x, y + vspeed, obj_wall))
{
    while (!place_meeting(x, y + sign(vspeed), obj_wall))
    {
        y += sign(vspeed)
    }
    vspeed = 0;
}
 
Last edited:

Joe Ellis

Member
It might happen because the first place meeting is checking for x collision, then changes x if there is, then checks for y collision, using x (potentially the new x after collision) So maybe it would work better if you set 2 temp variables: ox = x, oy = y. and use those instead in the place_meeting checks. That way the correct movement to contact with the walls will be applied on each axis, and the y check won't be affected by any x change during the x check before it. I think this is a more accurate way of judging the situation, cus each check is only dealing with one axis at a time
 

Paturicko

Member
Thanks for replying! I'm not sure what you mean so I'm sure I edited it wrong.

This is how I changed it but the player gets stuck in walls more now.

Code:
var ox = x;
var oy = y;

if (place_meeting(ox + hspeed, oy, obj_wall))
{
    while (!place_meeting(ox + sign(hspeed), oy, obj_wall))
    {
        x += sign(hspeed)
    }
    hspeed = 0;
}
if (place_meeting(ox, oy + vspeed, obj_wall))
{
    while (!place_meeting(ox, oy + sign(vspeed), obj_wall))
    {
        y += sign(vspeed)
    }
    vspeed = 0;
}
 

Rob

Member
@Paturicko

you're setting ox and oy as x/y and then checking for a collision with ox + hspeed / oy + vspeed.

But then when you're moving pixel by pixel, you're updating x/y by the sign of the speeds without updating ox/oy.

Just replace ox/oy with x/y if you don't need them for anything else or make sure that you update ox/oy every pixel instead of just x/y

The code inside the while loop can happen multiple times in the same step, so you're not updating ox/oy every pixel moved, if that's what you're thinking is happening at the top.
 
Last edited:

Sabnock

Member
Code:
if (place_meeting(x + hspeed, y, obj_wall))
{
    while (!place_meeting(x + sign(hspeed), y, obj_wall))
    {
        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 += sign(vspeed)
    }
    vspeed = 0;
}

y += vspeed;
you need to complete the move for x before you check the y else if you move x after checking y it maybe in a wall.
 

Paturicko

Member
@Paturicko

you're setting ox and oy as x/y and then checking for a collision with ox + hspeed / oy + vspeed.

But then when you're moving pixel by pixel, you're updating x/y by the sign of the speeds without updating ox/oy.

Just replace ox/oy with x/y if you don't need them for anything else or make sure that you update ox/oy every pixel instead of just x/y

The code inside the while loop can happen multiple times in the same step, so you're not updating ox/oy every pixel moved, if that's what you're thinking is happening at the top.
Code:
var ox = x;
var oy = y;

if (place_meeting(ox + hspeed, oy, obj_wall))
{
    while (!place_meeting(ox + sign(hspeed), oy, obj_wall))
    {
        ox += sign(hspeed)
    }
    hspeed = 0;
}
if (place_meeting(ox, oy + vspeed, obj_wall))
{
    while (!place_meeting(ox, oy + sign(vspeed), obj_wall))
    {
        oy += sign(vspeed)
    }
    vspeed = 0;
}
So I started updating ox & oy instead of x & y instead but it does the same thing as x & y.

I just found out how calculations for motion_add works.
hspeed += spd*cos(pi/180*dir);
vspeed -= spd*sin(pi/180*dir);

So I might redo my movement system to use x & y instead of hspeed and vspeed
 

Sabnock

Member
using hspeed and vspeed to move is the correct way to do it you just need to modify your collision code. the code i put above should work.
 

Paturicko

Member
using hspeed and vspeed to move is the correct way to do it you just need to modify your collision code. the code i put above should work.
Thanks! I tried yours but it didn't work at first but I just modified yours using variables like hspd and vspd instead of built in varibles and it works now.
 

Joe Ellis

Member
Sorry I meant for it to be used like this:

Code:
var ox = x;

if (place_meeting(x + hspeed, y, obj_wall))
{
    while (!place_meeting(x + sign(hspeed), y, obj_wall))
    {
        x += sign(hspeed)
    }
    hspeed = 0;
}
if (place_meeting(ox, y + vspeed, obj_wall))
{
    while (!place_meeting(ox, y + sign(vspeed), obj_wall))
    {
        y += sign(vspeed)
    }
    vspeed = 0;
}
I realized oy isn't actually needed here, and you just use ox to preserve the original x when doing the vertical check so it's not influenced by the horizontal check\movement of x. I don't know if it will actually work in this case, it's hard to tell without testing the whole project, but it was just an idea. I've used it before and it did work\or produce better results in a couple of cases.
 
Top