GMS 2.3+ oneway platforms that are also slopes

yashamatt

Member
So I have been fiddling with this for a while now, trying to adapt my spaghetti code to allow oneway platforms that are also slopes.
I am quite new to coding in general but I do have slopes and oneway platforms working properly in my side-scrolling platformer,
however, my oneway platforms that are also slopes still tend to bug with either it not registering properly when being fallen upon
or walked onto by an object (falls through). I am using object-based collision (opposed to tile-based - mainly because I didn't know
about tile-based collision when I started the project, also there won't be too many active objects at any one time in my small game).

Any tips or ideas on how to approach the problem or even just helping my code be better here will be much appreciated! Below is
the current working mess code that I am using without oneway slopes implemented.
My code is mainly an amalgamation of my own crap with hints from zack bell's 2014 blog and whatever I could shovel up in the forums here.

par_solid and o_oneway_up are separate children of par_collision.

GML:
/**************************************************************
* player STEP event
* the state code is actually in a large switch statement with scripts for each
* state but i just copied out what i thought might be relavant
**************************************************************/

if state != player.falling
{
    var underblock = instance_place(x,y+1,o_oneway);
    if !place_meeting(x,y+1,par_solid)
    {
        if instance_exists(underblock)
        {
            if bbox_bottom > underblock.bbox_top
            {
                state = player.falling;
                exit;      
            }
        }
        else if !instance_exists(underblock)
        {
            state = player.falling;
            exit;              
        }
    }
}

if state == player.falling
{
    var _semi_solid = instance_place(x,bbox_bottom+1,o_oneway_up)
    if (place_meeting(x,bbox_bottom+1,par_solid))
    or (instance_exists(_semi_solid) and _semi_solid.bbox_top>bbox_bottom)
    and ySpeed > 0
    {
        state = player.idle;
        exit;              
    }
}

ok here is the actual collision stuff

GML:
//Horizontal and up slopes
var y_gradient = 0;

while (place_meeting(x+xSpeed, y-y_gradient, par_solid) and y_gradient <= abs(1*xSpeed))
    y_gradient += 1;

if place_meeting(x+xSpeed, y-y_gradient, par_solid)
{
    while (!place_meeting(x+sign(xSpeed), y, par_solid)) x+=sign(xSpeed);
    xSpeed = 0;          
}
else
{
    y -= y_gradient;
}
x += xSpeed;

// Downward slopes
if !place_meeting(x,y,par_solid) and ySpeed >= 0 and place_meeting(x, y+2+abs(xSpeed), par_solid)
{
    while(!place_meeting(x,y+1,par_collision))
    {
        y += 1;
    }
}

//vertical
repeat (abs(ySpeed))
{
    var underblock = instance_place(x,y+1,o_oneway_up);
   
    if ((place_meeting(x, y + sign(ySpeed), o_oneway_up) and ySpeed > 0
    and !place_meeting(x, y, o_oneway_up) and instance_exists(underblock)
    and underblock.bbox_top>bbox_bottom))      
    {
        ySpeed = 0;
        break;
    }      
    else if !place_meeting(x, y + sign(ySpeed), par_solid)
    {
        y += sign(ySpeed);
    }
    else
    {
        ySpeed = 0;          
        break;
    }
}
 

Chourando

Member
My way of doing it: make two collision line (actualy single pixel rectangle line) checks: one just one pixel below player (aka ground check), other just above. If ground check collides with slope and above check is false - you're on slope, stop falling. For going down through just push pixel down regardles collisions. Then if ground and above collision checks are true - ignore collisions and will fall down through.

P.s. Other collisions should be ignored while colliding with one-way any type "through" platforms including slopes.
 

yashamatt

Member
My way of doing it: make two collision line (actualy single pixel rectangle line) checks: one just one pixel below player (aka ground check), other just above. If ground check collides with slope and above check is false - you're on slope, stop falling. For going down through just push pixel down regardles collisions. Then if ground and above collision checks are true - ignore collisions and will fall down through.

P.s. Other collisions should be ignored while colliding with one-way any type "through" platforms including slopes.
creating your own collision line/rectangle with the player seems alot better than using the collision object's bbox
judging from your description i'm imagining something along the lines of this:

GML:
is_on_block = collision_rectangle(bbox_left,bbox_bottom,bbox_right,bbox_bottom+1,par_collision,true,true);

//collisions
if instance_exists(is_on_block)
{
    if is_on_block.object_index == o_oneway_slope
        // oneway slope collision
    else if is_on_block.object_index == o_solid_slope
        // solid slope collision
    else if is_on_block.object_index == o_oneway_flat
        // oneway flat collision  
    else is_on_block.object_index == o_solid_flat
        // solid flat collision  
}
   
   
//state machine
if state == falling and instance_exists(is_on_block)
    state = idle;
 

Chourando

Member
The main difference between one-way and solid platforms is that you can't go through them only from one direction. Typical one-way platform is solid from above and from other sides is open to go through. That means that when entity is above platform/slope your collision code works the same as on solid paltform. The problem you need to solve is how to go through that other directions and how to pass/jump down that platform/slope. First thing is to find what kind of collision entity enters (solid or one-way), that stops from moving. Second - if it's one-way just ignore collision - simple. For pass/jump down - just push down 1 pixel as meantioned in earlier post. Longs story short - when collision code says stop moving - you check if it's one-way obstacle and don't stop.
 
Top