GML Help needed: Custom Collision and Walking of Ledges [SOLVED]

Hey everyone,

We are still new to GameMaker and have only released one game featuring simple rectangular collisions for player and platforms. We are working on a new game though that needs some different collision shapes.

I'm sure a solution to this has to be somewhere but, after spending most of the day trying to find something I think I've run out of keyword combinations to describe the issue. I just can't seem to find it.

Here's an example of what it happening now:


and here is the code driving it:
Code:
/// @description Insert description here

//Inputs
left=keyboard_check(vk_left);
right=keyboard_check(vk_right);
jump=keyboard_check_pressed(vk_space);

//Animation Reset
xscale=lerp(xscale,1,.25);
yscale=lerp(yscale,1,.25);

//Calculate Movement
var move=right-left;

//Left|Right Movement
if move!=0{
    if hsp<maxsp && move=1{
        hsp+=fric;
    }else if hsp>-maxsp && move=-1{
        hsp-=fric;
    }
} else {
    if hsp>0 && move=0{
        hsp-=fric;
    }else if hsp<0 && move=0{
        hsp+=fric;
    }
}

vsp=vsp+grv;

//Jump
if place_meeting(x,y+1,o_Solid) && jump {
    vsp=-jsp;
    xscale=.9;
    yscale=1.2;
    land=1;
}

//Horizontal Collision
if place_meeting(x+hsp,y,o_Solid){
    while (!place_meeting(x+sign(hsp),y,o_Solid)){
        x=x+sign(hsp);
    }
    hsp=0;
}

x=x+hsp;

//Vertical Collision
if place_meeting(x,y+vsp,o_Solid){
    while (!place_meeting(x,y+sign(vsp),o_Solid)){
        y=y+sign(vsp);
    }
    vsp=0;
    if land>0{
        xscale=1.05;
        yscale=.95;
        land-=.5;
    }      
}else{
    y=y+vsp;
   
}
Ideally the zombie should slide down off the ledge at a certain point. Any help would be greatly appreciated! I've never seen any tutorials for platformers that cover this.
 

jo-thijs

Member
Hey everyone,

We are still new to GameMaker and have only released one game featuring simple rectangular collisions for player and platforms. We are working on a new game though that needs some different collision shapes.

I'm sure a solution to this has to be somewhere but, after spending most of the day trying to find something I think I've run out of keyword combinations to describe the issue. I just can't seem to find it.

Here's an example of what it happening now:


and here is the code driving it:
Code:
/// @description Insert description here

//Inputs
left=keyboard_check(vk_left);
right=keyboard_check(vk_right);
jump=keyboard_check_pressed(vk_space);

//Animation Reset
xscale=lerp(xscale,1,.25);
yscale=lerp(yscale,1,.25);

//Calculate Movement
var move=right-left;

//Left|Right Movement
if move!=0{
    if hsp<maxsp && move=1{
        hsp+=fric;
    }else if hsp>-maxsp && move=-1{
        hsp-=fric;
    }
} else {
    if hsp>0 && move=0{
        hsp-=fric;
    }else if hsp<0 && move=0{
        hsp+=fric;
    }
}

vsp=vsp+grv;

//Jump
if place_meeting(x,y+1,o_Solid) && jump {
    vsp=-jsp;
    xscale=.9;
    yscale=1.2;
    land=1;
}

//Horizontal Collision
if place_meeting(x+hsp,y,o_Solid){
    while (!place_meeting(x+sign(hsp),y,o_Solid)){
        x=x+sign(hsp);
    }
    hsp=0;
}

x=x+hsp;

//Vertical Collision
if place_meeting(x,y+vsp,o_Solid){
    while (!place_meeting(x,y+sign(vsp),o_Solid)){
        y=y+sign(vsp);
    }
    vsp=0;
    if land>0{
        xscale=1.05;
        yscale=.95;
        land-=.5;
    }     
}else{
    y=y+vsp;
  
}
Ideally the zombie should slide down off the ledge at a certain point. Any help would be greatly appreciated! I've never seen any tutorials for platformers that cover this.
I don't like using the sprite shapes themselves as collision masks instead of some simple rectangles or circles.
They've been the cause of so many bugs already, either because the shape changes as the animation progresses, but the collision code doesn't account for this
or because collisions with non-rectangular collision masks just make things more awkward, because of parts sticking out (as your issue demonstrates) or because of the pixelated nature of sprites.

Anyway, if you're looking for a quick fix with sprite collisions after all,
the main issue you'll run into is to determin if the player is still with their feet on the floor or if it is a different body part that is touching the floor (this is difficult because of how tiny the feet are and how flat the body is.
One way to easily get around this is to add a new sprite that is a copy (in shape of the feet of) of the player where the collision mask is manually set to correspond with the feet of the player.
I'll refer to this sprite as s_PlayerFeetMask.
One quick fix would then be to replace your vertical collision code:
Code:
//Vertical Collision
if place_meeting(x,y+vsp,o_Solid){
    while (!place_meeting(x,y+sign(vsp),o_Solid)){
        y=y+sign(vsp);
    }
    vsp=0;
    if land>0{
        xscale=1.05;
        yscale=.95;
        land-=.5;
    }     
}else{
    y=y+vsp;
  
}
with:
Code:
//Vertical Collision
if place_meeting(x, y + vsp, o_Solid) {
    while true {
        if abs(y - yprevious) >= abs(vsp) {
            break;
        }
        if place_meeting(x, y + sign(vsp), o_Solid) {
            if vsp > 0 {
                var pmask = mask_index;
                mask_index = s_PlayerFeetMask;
                var b = place_meeting(x, y + 1, o_Solid);
                mask_index = pmask;
                if !b {
                    var px = x;
                    while true {
                        x -= 1;
                        if place_meeting(x, y, o_Solid) {
                            b = false;
                            break;
                        }
                        if !place_meeting(x, y + 1, o_Solid) {
                            b = true;
                            break;
                        }
                    }
                    if b {
                        continue;
                    }
                    x = px;
                    while true {
                        x += 1;
                        if place_meeting(x, y, o_Solid) {
                            b = false;
                            break;
                        }
                        if !place_meeting(x, y + 1, o_Solid) {
                            b = true;
                            break;
                        }
                    }
                    if b {
                        continue;
                    }
                    x = px;
                }
            }
            break;
        }
        y = y + sign(vsp);
    }
    if abs(y - yprevious) < abs(vsp) {
        vsp = 0;
        if land > 0 {
            xscale = 1.05;
            yscale = .95;
            land -= .5;
        }
    }
} else {
    y = y + vsp;
}
The effect you get from this is not physically accurate and it may contain bugs, depending on how you use it.
But perhaps this is what you were seeking for, so let me know.

On a side note, you can shorten your horizontal movement code:
Code:
//Left|Right Movement
if move!=0{
    if hsp<maxsp && move=1{
        hsp+=fric;
    }else if hsp>-maxsp && move=-1{
        hsp-=fric;
    }
} else {
    if hsp>0 && move=0{
        hsp-=fric;
    }else if hsp<0 && move=0{
        hsp+=fric;
    }
}
to:
Code:
//Left|Right Movement
if move != 0 {
    if hsp * move < maxsp {
        hsp += move * fric;
    }
} else {
    hsp -= sign(hsp) * fric;
}
 
Both code snippets you provided worked like magic!

Can't thank you enough! This is going to same so much time with the other oddly shaped characters!
 
Well, I did find one bug that only happens on the first ledge so it looks like a great opportunity to study and dissect the code you provided. :)

Thanks Again!
 
I don't like using the sprite shapes themselves as collision masks instead of some simple rectangles or circles.
They've been the cause of so many bugs already, either because the shape changes as the animation progresses, but the collision code doesn't account for this
or because collisions with non-rectangular collision masks just make things more awkward, because of parts sticking out (as your issue demonstrates) or because of the pixelated nature of sprites.

Anyway, if you're looking for a quick fix with sprite collisions after all,
the main issue you'll run into is to determin if the player is still with their feet on the floor or if it is a different body part that is touching the floor (this is difficult because of how tiny the feet are and how flat the body is.
One way to easily get around this is to add a new sprite that is a copy (in shape of the feet of) of the player where the collision mask is manually set to correspond with the feet of the player.
I'll refer to this sprite as s_PlayerFeetMask.
One quick fix would then be to replace your vertical collision code:
Code:
//Vertical Collision
if place_meeting(x,y+vsp,o_Solid){
    while (!place_meeting(x,y+sign(vsp),o_Solid)){
        y=y+sign(vsp);
    }
    vsp=0;
    if land>0{
        xscale=1.05;
        yscale=.95;
        land-=.5;
    }   
}else{
    y=y+vsp;
 
}
with:
Code:
//Vertical Collision
if place_meeting(x, y + vsp, o_Solid) {
    while true {
        if abs(y - yprevious) >= abs(vsp) {
            break;
        }
        if place_meeting(x, y + sign(vsp), o_Solid) {
            if vsp > 0 {
                var pmask = mask_index;
                mask_index = s_PlayerFeetMask;
                var b = place_meeting(x, y + 1, o_Solid);
                mask_index = pmask;
                if !b {
                    var px = x;
                    while true {
                        x -= 1;
                        if place_meeting(x, y, o_Solid) {
                            b = false;
                            break;
                        }
                        if !place_meeting(x, y + 1, o_Solid) {
                            b = true;
                            break;
                        }
                    }
                    if b {
                        continue;
                    }
                    x = px;
                    while true {
                        x += 1;
                        if place_meeting(x, y, o_Solid) {
                            b = false;
                            break;
                        }
                        if !place_meeting(x, y + 1, o_Solid) {
                            b = true;
                            break;
                        }
                    }
                    if b {
                        continue;
                    }
                    x = px;
                }
            }
            break;
        }
        y = y + sign(vsp);
    }
    if abs(y - yprevious) < abs(vsp) {
        vsp = 0;
        if land > 0 {
            xscale = 1.05;
            yscale = .95;
            land -= .5;
        }
    }
} else {
    y = y + vsp;
}
The effect you get from this is not physically accurate and it may contain bugs, depending on how you use it.
But perhaps this is what you were seeking for, so let me know.

So we've run up against a wall here. Found this bug that we can't see to get rid of. It only happened when walking off the right side AND ONLY if there is no solid to the left.

https://gifs.com/gif/collision-issue-pt2-G5AjOJ

This time I made the collision shape visible. It's a 45 degree slope on both sides.

What section of the code do you think would cause this? I can't figure out where to start looking.
 

jo-thijs

Member
So we've run up against a wall here. Found this bug that we can't see to get rid of. It only happened when walking off the right side AND ONLY if there is no solid to the left.

https://gifs.com/gif/collision-issue-pt2-G5AjOJ

This time I made the collision shape visible. It's a 45 degree slope on both sides.

What section of the code do you think would cause this? I can't figure out where to start looking.
This happens whenever you fall at the floor, but not with your feet and your feet are above the the floor.

This can have 2 causes as far as I can think of right now.
1) You made a mistake in the feet mask, it should be the entire bottom line of the sprite in this case.
2) You're experiencing problems with collision checking in GameMaker not liking decimals in coordinates.

Can you confirm your feet mask is indeed correct?
 
This happens whenever you fall at the floor, but not with your feet and your feet are above the the floor.

This can have 2 causes as far as I can think of right now.
1) You made a mistake in the feet mask, it should be the entire bottom line of the sprite in this case.
2) You're experiencing problems with collision checking in GameMaker not liking decimals in coordinates.

Can you confirm your feet mask is indeed correct?
Spot on! Looks like my feet mask had two extra pixels on the sides making it slightly longer than my player's collision area. Can't seem to replicate the bug after fixing this. :D
 
Top