[Solved] Player get stuck when go up slopes straight to wall.

Discussion in 'Programming' started by Edwin, May 29, 2019.

  1. Edwin

    Edwin Member

    Joined:
    Jul 15, 2018
    Posts:
    406
    Hey, it's me, Edwin again. yey

    So basically a weird problem that I have is when player goes up via slope, and then right after it player collide with the wall, player get stuck.

    It looks like this:

    [​IMG]

    This is my Step Event code:
    Code:
    /// Step Event
    
    // Movement
    if (keyboard_check(vk_right) && !keyboard_check(vk_left)) {
        hspd = 9;
    } else
    if (keyboard_check(vk_left) && !keyboard_check(vk_right)) {
        hspd = -9;
    }
    
    // Check not moving
    if ((!keyboard_check(vk_right) && !keyboard_check(vk_left)) || (keyboard_check(vk_right) && keyboard_check(vk_left))) {
        hspd = 0;
    }
    
    // Gravity
    if (!place_meeting(x, y+1, parent_ground)) {
        vspd += grav;
    }
    
    // Jumping
    if (place_meeting(x, y+1, parent_ground)) {
        if (keyboard_check_pressed(vk_up)) {
            vspd = -20;
        }
    }
    
    // Jump cancel
    if (vspd < 0) {
        if (keyboard_check_released(vk_up)) {
            vspd *= 0.4;
        }
    }
    
    // Variables
    var hspd_final = hspd;
    
    // Horizontal collision
    horizontal_collision = instance_place(x+hspd_final, y, parent_ground);
    if (horizontal_collision != noone) {
        if (horizontal_collision.object_index == object_ground) {
            while (!place_meeting(x+sign(hspd_final), y, horizontal_collision)) {
                x += sign(hspd_final);
            }
            hspd_final = 0;
        } else {
            // Declare yplus
            yplus = 0;
           
            // Loop
            while (place_meeting(x+hspd_final, y-yplus, parent_ground) && yplus <= abs(1*hspd_final)) {
                yplus += 1;
            }
            y -= yplus;
            while (place_meeting(x, y+1, parent_ground)) {
                y -= 1;
            }
        }
    }
    
    // Down slope
    down_slope = instance_place(x, y+1, parent_ground);
    if (down_slope != noone && down_slope.object_index != object_ground) {
        if (place_meeting(x, y+1, parent_ground)) {
            yminus = abs(hspd_final);
           
            while (place_meeting(x+hspd_final, y+yminus, parent_ground) && yminus != 0) {
                yminus --;
            }
           
            y += yminus;
        }
    }
    
    // Initialize horizontal speed
    x += hspd_final;
    
    // Vertical collision
    if (place_meeting(x, y+vspd, parent_ground)) {
        while (!place_meeting(x, y+sign(vspd), parent_ground)) {
            y += sign(vspd);
        }
        vspd = 0;
    }
    
    // Initialize vertical speed
    y += vspd;
    
    I think some variables like hspd, vspd aren't really matter here so you can declare them by yourself. But objects like parent_ground, object_ground, object_slope are more important:
    • parent_ground is a parent object which childs are object_ground and object_slope;
    • object_ground is a simple block object as basically in other infinite amount of games.
    • object_slope is a slope with built-in precise collision.
    Thank you for the help.
     
  2. jo-thijs

    jo-thijs Member

    Joined:
    Jun 20, 2016
    Posts:
    2,844
    You only use this code:
    Code:
            while (place_meeting(x+hspd_final, y-yplus, parent_ground) && yplus <= abs(1*hspd_final)) {
                yplus += 1;
            }
            y -= yplus;
    when no collision with a ground instance has been detected, so slopes are ignored in collisions with ground instances.
    If you change parent_ground to object_slope in this code, you can apply it to both collision responses and solve (at least partially) the issue you're having.
    Code:
    // Horizontal collision
    horizontal_collision = instance_place(x+hspd_final, y, parent_ground);
    if (horizontal_collision != noone) {
        // Declare yplus
        yplus = 0;
       
        // Loop
        while (place_meeting(x+hspd_final, y-yplus, object_ground) && yplus <= abs(1*hspd_final)) {
            yplus += 1;
        }
        y -= yplus;
       
        if (horizontal_collision.object_index == object_ground) {
            while (!place_meeting(x+sign(hspd_final), y, horizontal_collision)) {
                x += sign(hspd_final);
            }
            hspd_final = 0;
        } else {
            while (place_meeting(x, y+1, parent_ground)) {
                y -= 1;
            }
        }
    }
    EDIT: Fixed a mistake in my code above.
     
    Last edited: May 29, 2019
    Edwin likes this.
  3. Edwin

    Edwin Member

    Joined:
    Jul 15, 2018
    Posts:
    406
    Hm. Now my game simply freezes after that multi collision. And my player jumps if he collides with object_ground without being on a slope. Well, nevertheless thank you, yet you already helped me.
     
  4. Edwin

    Edwin Member

    Joined:
    Jul 15, 2018
    Posts:
    406
    Maybe after 500+ years someone will fix this, but now the problem is not so terrible, you know.
     
  5. jo-thijs

    jo-thijs Member

    Joined:
    Jun 20, 2016
    Posts:
    2,844
    You're right. An oversight of me.

    The easiest fix is to put a limit on the amount of pixels the player can horizontally move towards a ground instance:
    Code:
    // Horizontal collision
    horizontal_collision = instance_place(x+hspd_final, y, parent_ground);
    if (horizontal_collision != noone) {
        // Declare yplus
        yplus = 0;
     
        // Loop
        while (place_meeting(x+hspd_final, y-yplus, object_ground) && yplus <= abs(1*hspd_final)) {
            yplus += 1;
        }
        y -= yplus;
     
        if (horizontal_collision.object_index == object_ground) {
            while (!place_meeting(x+sign(hspd_final), y, horizontal_collision) && abs(x - xprevious) < abs(hspd_final)) {
                x += sign(hspd_final);
            }
            hspd_final = 0;
        } else {
            while (place_meeting(x, y+1, parent_ground)) {
                y -= 1;
            }
        }
    }
    I'm not sure what you're trying to say here.
     
  6. Edwin

    Edwin Member

    Joined:
    Jul 15, 2018
    Posts:
    406
    Now when I collide a wall player goes through it.
     
  7. jo-thijs

    jo-thijs Member

    Joined:
    Jun 20, 2016
    Posts:
    2,844
    My bad, in the while loop:
    Code:
        while (place_meeting(x+hspd_final, y-yplus, object_ground) && yplus <= abs(1*hspd_final)) {
    I meant to write object_slope, rather than object_ground.

    EDIT:
    And you'll probably also want to change horizontal_collision to parent_ground in this line:
    Code:
            while (!place_meeting(x+sign(hspd_final), y, horizontal_collision) && abs(x - xprevious) < abs(hspd_final)) {
     
    Last edited: May 30, 2019
  8. Edwin

    Edwin Member

    Joined:
    Jul 15, 2018
    Posts:
    406
    Looks like, to get stuck in the wall, I don't even need acceleration anymore.
    [​IMG]

    But anyway thank you that you do care. Maybe game just can't handle multiple collisions occurring at the same time.
     
  9. jo-thijs

    jo-thijs Member

    Joined:
    Jun 20, 2016
    Posts:
    2,844
    What do you mean with acceleration?
    The player doesn't have acceleration.

    Anyway, I tested my last proposed solution and it works for me, I did not get stuck.
    Can you confirm that you're using the code I suggested by uploading your current step event?
    Is there some other relevant code in your project?
     
    Edwin likes this.
  10. Edwin

    Edwin Member

    Joined:
    Jul 15, 2018
    Posts:
    406
    I added acceleration for hspd just for a test, guess that is the problem. In a collision if the speed is an odd value, the player stuck.
     
  11. Edwin

    Edwin Member

    Joined:
    Jul 15, 2018
    Posts:
    406
    This is my Step Event right now:
    Code:
    /// Step Event
    
    // Movement
    if (keyboard_check(vk_right) && !keyboard_check(vk_left)) {
        hspd = 7; // 7 divide 2 is 3.5 so the game is kinda difficult to calculate subpixels, i guess
    } else
    if (keyboard_check(vk_left) && !keyboard_check(vk_right)) {
        hspd = -7;
    }
    
    // Check not moving
    if ((!keyboard_check(vk_right) && !keyboard_check(vk_left)) || (keyboard_check(vk_right) && keyboard_check(vk_left))) {
        hspd = 0;
    }
    
    // Gravity
    if (!place_meeting(x, y+1, parent_ground)) {
        vspd += grav;
    }
    
    // Jumping
    if (place_meeting(x, y+1, parent_ground)) {
        if (keyboard_check_pressed(vk_up)) {
            vspd = -20;
        }
    }
    
    // Jump cancel
    if (vspd < 0) {
        if (keyboard_check_released(vk_up)) {
            vspd *= 0.4;
        }
    }
    
    // Variables
    var hspd_final = hspd;
    
    // Horizontal collision
    var horizontal_collision = instance_place(x+hspd_final, y, parent_ground);
    
    if (horizontal_collision != noone) {
        // Declare yplus
        yplus = 0;
        // Loop
        if (horizontal_collision.object_index != object_ground) {
            while (place_meeting(x+hspd_final, y-yplus, parent_ground) && yplus <= abs(1*hspd_final)) {
                yplus += 1;
            }
        }
        y -= yplus;
        if (horizontal_collision.object_index == object_ground) {
            while (!place_meeting(x+sign(hspd_final), y, object_ground) && abs(x - xprevious) < abs(hspd_final)) {
                x += sign(hspd_final);
            }
            hspd_final = 0;
        } else {
            while (place_meeting(x, y+1, parent_ground)) {
                y -= 1;
            }
        }
    }
    
    // Down slope
    down_slope = instance_place(x, y+1, parent_ground);
    if (down_slope != noone && down_slope.object_index != object_ground) {
        if (place_meeting(x, y+1, parent_ground)) {
            yminus = abs(hspd_final);
        
            while (place_meeting(x+hspd_final, y+yminus, parent_ground) && yminus != 0) {
                yminus --;
            }
        
            y += yminus;
        }
    }
    
    // Initialize horizontal speed
    x += hspd_final;
    
    // Vertical collision
    if (place_meeting(x, y+vspd, parent_ground)) {
        while (!place_meeting(x, y+sign(vspd), parent_ground)) {
            y += sign(vspd);
        }
        vspd = 0;
    }
    
    // Initialize vertical speed
    y += vspd;
    
    You can see my hspd is 7 (odd value). It does work if hspd is for example 6 or any other even number.

    Edit: by the way, I don't have object called object_slope because I have multiple of them (left side, right side, upside down etc) so I just use parent_ground instead of it.
     
    Last edited: May 30, 2019
  12. jo-thijs

    jo-thijs Member

    Joined:
    Jun 20, 2016
    Posts:
    2,844
    There are 3 differences with what I suggested:
    1) You have an additional if-statement around the slope loop:
    Code:
        // Loop
        if (horizontal_collision.object_index != object_ground) {
            ...
        }
    2) In the slope loop, you check for parent_ground instead of object_slope.
    3) In the ground loop, you check for object_ground, rather than parent_ground.

    Try this instead:
    Code:
    // Horizontal collision
    horizontal_collision = instance_place(x+hspd_final, y, parent_ground);
    if (horizontal_collision != noone) {
        // Declare yplus
        yplus = 0;
     
        // Loop
        while (place_meeting(x+hspd_final, y-yplus, object_slope) && yplus <= abs(1*hspd_final)) {
            yplus += 1;
        }
        y -= yplus;
     
        if (horizontal_collision.object_index == object_ground) {
            while (!place_meeting(x+sign(hspd_final), y, parent_ground) && abs(x - xprevious) < abs(hspd_final)) {
                x += sign(hspd_final);
            }
            hspd_final = 0;
        } else {
            while (place_meeting(x, y+1, parent_ground)) {
                y -= 1;
            }
        }
    }
     
    Edwin likes this.
  13. Edwin

    Edwin Member

    Joined:
    Jul 15, 2018
    Posts:
    406
    I don't have object called object_slope. They are multiple: object_slope1, object_slope2, etc. What should I do?
     
  14. jo-thijs

    jo-thijs Member

    Joined:
    Jun 20, 2016
    Posts:
    2,844
    Ah, I thought you had an object called object_slope because of:
    No problem though, create a parent object parent_slope that is the parent of each slope object and use that instead of object_slope.
    Also make sure to make parent_ground the parent of parent_slope.
     
    Edwin likes this.
  15. Edwin

    Edwin Member

    Joined:
    Jul 15, 2018
    Posts:
    406
    Still does not work correctly. if you have time for it, I could share you my project: Google Drive. Please I am probably just doing something wrong, but you can find out exactly what in details if you want. Thanks.
     
  16. jo-thijs

    jo-thijs Member

    Joined:
    Jun 20, 2016
    Posts:
    2,844
    It's fixed if you don't make a distinction between what you're colliding with:
    Code:
    if (horizontal_collision != noone) {
        // Declare yplus
        yplus = 0;
     
        // Loop
        while (place_meeting(x+hspd_final, y-yplus, parent_slope) && yplus <= abs(1*hspd_final)) {
            yplus += 1;
        }
        y -= yplus;
     
        while (!place_meeting(x+sign(hspd_final), y, parent_ground) && abs(x - xprevious) < abs(hspd_final)) {
            x += sign(hspd_final);
        }
        hspd_final = 0;
    }
     
    Edwin likes this.
  17. NeZvers

    NeZvers Member

    Joined:
    Mar 24, 2018
    Posts:
    320
  18. Edwin

    Edwin Member

    Joined:
    Jul 15, 2018
    Posts:
    406
    Yes, it worked! Thank you! :)
     
  19. Edwin

    Edwin Member

    Joined:
    Jul 15, 2018
    Posts:
    406
  20. NeZvers

    NeZvers Member

    Joined:
    Mar 24, 2018
    Posts:
    320
    Each time you call place_meeting/ instance_place/ etc. all the instances of the object you are checking against are doing checks if they are in a position to collide. Now in that while loop each time it repeats it goes through all instances to check if you are colliding with any of them.
    That's why superior collision system is so-called grid collision or if you have GMS2 then you have the option to do tile collision (Shoun Spalding have a tutorial on that). But if you are new to programming or to Gamemaker it's ok to use this "traditional" collision, because many published GM games have done it, although keep in mind you can save much with better collision.
     

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