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

Discussion in 'Programming' started by Paturicko, Jan 11, 2020 at 9:25 PM.

  1. Paturicko

    Paturicko Member

    Joined:
    Saturday
    Posts:
    4
    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: Jan 11, 2020 at 10:59 PM
  2. Joe Ellis

    Joe Ellis Member

    Joined:
    Aug 30, 2016
    Posts:
    1,036
    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 likes this.
  3. Paturicko

    Paturicko Member

    Joined:
    Saturday
    Posts:
    4
    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;
    }
     
  4. Rob

    Rob Member

    Joined:
    Jul 12, 2016
    Posts:
    741
    @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: Jan 12, 2020 at 7:10 PM
    Paturicko likes this.
  5. Sabnock

    Sabnock Member

    Joined:
    Jul 21, 2016
    Posts:
    344
    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 likes this.
  6. Paturicko

    Paturicko Member

    Joined:
    Saturday
    Posts:
    4
    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
     
  7. Sabnock

    Sabnock Member

    Joined:
    Jul 21, 2016
    Posts:
    344
    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.
     
  8. Paturicko

    Paturicko Member

    Joined:
    Saturday
    Posts:
    4
    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.
     
  9. Sabnock

    Sabnock Member

    Joined:
    Jul 21, 2016
    Posts:
    344
    makes sense. i never use those built in variables.
     
  10. Joe Ellis

    Joe Ellis Member

    Joined:
    Aug 30, 2016
    Posts:
    1,036
    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.
     
    Paturicko likes this.

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice