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

GML Random issues with one-way platforms

E

Enagic

Guest
Hi there! I've been searching for a nice way to handle one-way platforms for a while, and the most efficient and versatile that I've found has been this:

Code:
with(obj_platform) {
    if place_meeting(x,y-other.vspd,other) and !place_meeting(x,y,other) {
        while !place_meeting(x,y-1,other) {
            other.y += 1;
        }
        other.vspd = 0;
    }
}
y += vspd;
Basically the collision check is made by the platform itself, so every object should be able to collide with it, and there's no problem with two platforms one in top of the other.
However, the only issue is that at random moments the player will pass through the platform. Is really rare though, but it still happen at times in any platform and in any moment. I've checked with different vertical speeds, different timings, different positions, and it seems to be totally random (I know it's not actually random, but it seems like that).

It's worth to say that this code is only applied in the aereal state of the player, but that doesn't look like the problem, since the player won't stop either, not even for a single frame. It's just like if the platform wasn't there.

Also, using +1 instead of +sign(other.vspd) isn't the problem either. This bug happens either way.

So, any thoughts? I've been scraching my head for a while now, and I couldn't figure anything yet. Any help would be heavily appreciated :)
 

sp202

Member
"other" refers to the other object in a collision event, so I don't think it has any use in predicting collisions the way you're using it as it'll return no one unless the player is already colliding with it. I think having the platform detect collisions is dangerous when it comes to multiple objects colliding at once, would really mess up your use of "other".
 

TheouAegis

Member
The other in his code is referring to the player. He used with() at the start. but I am pretty sure you need to use other.id in your place_meeting() calls. Also you need to break the with() loop when a platform is landed upon.
 
E

Enagic

Guest
Thanks for the replies! Although, using other.id and break doesn't make any difference. It still work pretty well the majority of the time, but sometimes it just randomly doesn't work.

Here's an example of it working well:


(Platforms are highlighted in purple, and the mask of the player is in aqua)

And here the player pass through it:



I just can't notice what's going wrong ):
I even tried rounding the position of the player so it doesn't exceed the bounding box of the platform, but it still happens some times.

Anyway, thanks for the help!
 

TheouAegis

Member
What if you do this?
Code:
with(obj_platform) {
   if place_meeting(x,y-other.vspd,other) and !place_meeting(x,y,other) {
        other.y += bbox_top - other.bbox_bottom - 1;
        other.vspd = 0;
        break;
    }
}
y += vspd;
And since you mvoe y based on the vspd here, is this the only code with y+=vspd and is this at the very end of your Step Event?
 
E

Enagic

Guest
Sadly, that works exactly the same ): Works well overall, but sometimes it doesn't happen anything.
And yes, that y+=vspd is at the end of the vertical collisions and is the only one that is on the step event.
 

TheouAegis

Member
Then I think it's the first place_meeting...
Try...

Code:
if vspd > 0
with(obj_platform) {
  if place_meeting(other.x, other.y+other.vspd, id) and !place_meeting(x,y,other) {
        other.y += bbox_top - other.bbox_bottom - 1;
        other.vspd = 0;
        break;
    }
}
y += vspd;
 
E

Enagic

Guest
Nope, now it doesn't work at all ):

Thanks for the help anyways, buddy!
 

TheouAegis

Member
Hahah I just realized how backward my code was.

Code:
if vspd > 0
{
    var x1 = bbox_left;
    var x2 = bbox_right;
    var y1 = bbox_bottom + vspd + 1;
    var y2 = bbox_bottom + 1;
    with obj_platform if collision_line(x1,y1,x2,y1,id,0,0) && !collision_line(x1,y2,x2,y2,id,0,0)
    {
        other.y += bbox_top - other.bbox_bottom - 1;
        other.vspd = 0;
        break;
    }
}
Try this one.
I do things differently based on my own styles, so I'm trying to work with other more general styles. I'm going back to my roots here, using collision_line since all you need to worry about is the collision at the bottom of the player, not the rest of it.


Alternatively:
Code:
if vspd > 0
{ 
    var x1 = bbox_left, x2 = bbox_right, y1 = bbox_bottom, y2 = bbox_bottom + vspd;
    with obj_platform 
        if x1 < bbox_right && bbox_left < x2 && y1 < bbox_top && bbox_top < y2
        {
            other.y += bbox_top - other.bbox_bottom - 1;
            other.vspd = 0;
            break;
        }
}
This should do nearly the same thing.
 
T

TimothyAllen

Guest
Hahah I just realized how backward my code was.

Code:
if vspd > 0
{
    var x1 = bbox_left;
    var x2 = bbox_right;
    var y1 = bbox_bottom + vspd + 1;
    var y2 = bbox_bottom + 1;
    with obj_platform if collision_line(x1,y1,x2,y1,id,0,0) && !collision_line(x1,y2,x2,y2,id,0,0)
    {
        other.y += bbox_top - other.bbox_bottom - 1;
        other.vspd = 0;
        break;
    }
}
Try this one.
I do things differently based on my own styles, so I'm trying to work with other more general styles. I'm going back to my roots here, using collision_line since all you need to worry about is the collision at the bottom of the player, not the rest of it.


Alternatively:
Code:
if vspd > 0
{
    var x1 = bbox_left, x2 = bbox_right, y1 = bbox_bottom, y2 = bbox_bottom + vspd;
    with obj_platform
        if x1 < bbox_right && bbox_left < x2 && y1 < bbox_top && bbox_top < y2
        {
            other.y += bbox_top - other.bbox_bottom - 1;
            other.vspd = 0;
            break;
        }
}
This should do nearly the same thing.
I would assume part of his issue is that his y value is not an integer value. So instead of adding to the characters y to move it onto the platform, i would set the y value directly to ensure its an integer value. Just on observation and might not change anything.
 

TheouAegis

Member
He was saying he tried to round off the coordinates, I think (in one of the posts here). But like I said, I personally just prefer comparing relevant bounds.
 
T

TimothyAllen

Guest
He was saying he tried to round off the coordinates, I think (in one of the posts here). But like I said, I personally just prefer comparing relevant bounds.
I didnt mean your conditions. I meant the final result.
 
Top