Playing Can Get Stuck in Wall When Moving Vertically

These are my physics functions

GML:
//this function gives an object gravity and sets a varible if they're in a state of falling.
//Each instance that uses it must set their own grav and vspd values at some point before it's called 

function gravity_scp(){

//see if falling and declare if so
if vspd > -1 {
    vdir = 1;
}


//apply gravity
if vspd < 5 {
vspd += grav; 
}


//find ground and land on it, setting vsp to 0 once feet are planted 

if place_meeting (x, y+vspd, Solid_Floor_Obj) {

  
    while !place_meeting (x, y+sign(vdir), Solid_Floor_Obj) {
    y += sign(vdir)
    }

vspd = 0;
}


//apply vertical movement
y += vspd;
}





//finds wall and stops against it
//each object using this much have a directional value set
function wall_collisons_scp(){

//normal block
if place_meeting (x+4*hdir, y, Solid_Floor_Obj) {

    

    while !place_meeting (x+sign(hdir), y, Solid_Floor_Obj) {
        x += sign(hdir)
        }

    hspd = 0;
    }
    
}


I have this weird bug I'm just now noticing where hitting a wall (ie: the side of a block) when the vspd isn't 0 can make her get stuck partially inside it and just freeze there with no ability to move
 
I think I may have fixed it by changing x+4 to x+hspd*hdir but I'll Ieave this up for a second opinion to make there's not some other catastrophic mistake I'm missing
 

Slyddar

Member
Everything you've been asking about here, and other threads, has been solved already in many platform tutorials on youtube. Any reason you are not just following those?
 
Everything you've been asking about here, and other threads, has been solved already in many platform tutorials on youtube. Any reason you are not just following those?
I have and Heartbeasts tutorials is where I got the base for a lot of my code from

But some things either aren't executed in a way that pertains to how I want them to mechanically function in my game or not explained in a way that clicks with me to understand it. Getting second opinions that explain it different ways helps me with that.

Plus I've heard so many GML Youtubers criticized here for allegedly teaching bad practices that I'm not entirely sure which ones to trust not to leave making some catastrophic coding mistake
 

Mk.2

Member
First, assuming that vdir and hdir are only ever given the values 1, -1 or 0, you should read up on the purpose of the sign function.

Second, this type of collision method normally uses "sign(vspd)" in both places where you've used "sign(vdir)", same for sign(hspd)/sign(hdir) in the horizontal collision. Also, it should simply be "x+hspd" in the place_meeting in the first line of horizontal collision code, assuming hspd is positive when moving to the right, negative when moving to the left.

Since you might be using these variables in a different way than I've assumed, post the rest of the code that deals with them if my suggestion didn't solve your issue.
 
First, assuming that vdir and hdir are only ever given the values 1, -1 or 0, you should read up on the purpose of the sign function.

Second, this type of collision method normally uses "sign(vspd)" in both places where you've used "sign(vdir)", same for sign(hspd)/sign(hdir) in the horizontal collision. Also, it should simply be "x+hspd" in the place_meeting in the first line of horizontal collision code, assuming hspd is positive when moving to the right, negative when moving to the left.

Since you might be using these variables in a different way than I've assumed, post the rest of the code that deals with them if my suggestion didn't solve your issue.
I can actually explain the first one, my hspd direction is decided when it's applied with x += hspd*hdir so it's always a positive. That means my physics code has to do the same math to know which direction the player is moving.

As for the Sign thing, I know it's not needed and I should change it to x+vdir/hdir but I'm almost afraid of breaking something unintended if I do. I'll do that and make sure it still works.
 

Nidoking

Member
if vspd > -1 { vdir = 1; }
So... if vspd is zero, vdir is one. If vspd is -0.5, meaning that the instance is still moving upward less than one pixel per step, vdir is one, indicating downward movement.

Then, AFTER determining vdir, you adjust vspd by your gravity value, so your vdir isn't derived from the correct vspd anyway. I suppose that if your gravity value is always something close to one, then this makes sense as one of those "it works and I don't know why, so I'll leave it that way" not-solutions you might get after not thinking enough about the order of operations.

The point that was made about the hdir and vdir variables is this: Please explain, in actual detail, a case in which you need the vdir or hdir value and the result of sign(hspd) or sign(vspd) would not work for you. There is no reason to store that in a separate variable unless you're going to need to know later what it was earlier, as in you're intentionally going to set them to different things. Best practice, in my mind, would be to eliminate the dir variables entirely and use only the spd variables and calls to sign. That could eliminate some of your problems. Fixing your order of operations might also help. Replacing 4 with hspd fixing things suggests that perhaps your hspd was not exactly equal to 4 at that time - the point of using functions for this is so that you can change the values and they'll still work. Hardcoding speed values breaks that.
 
So... if vspd is zero, vdir is one. If vspd is -0.5, meaning that the instance is still moving upward less than one pixel per step, vdir is one, indicating downward movement.

Then, AFTER determining vdir, you adjust vspd by your gravity value, so your vdir isn't derived from the correct vspd anyway. I suppose that if your gravity value is always something close to one, then this makes sense as one of those "it works and I don't know why, so I'll leave it that way" not-solutions you might get after not thinking enough about the order of operations.

The point that was made about the hdir and vdir variables is this: Please explain, in actual detail, a case in which you need the vdir or hdir value and the result of sign(hspd) or sign(vspd) would not work for you. There is no reason to store that in a separate variable unless you're going to need to know later what it was earlier, as in you're intentionally going to set them to different things. Best practice, in my mind, would be to eliminate the dir variables entirely and use only the spd variables and calls to sign. That could eliminate some of your problems. Fixing your order of operations might also help. Replacing 4 with hspd fixing things suggests that perhaps your hspd was not exactly equal to 4 at that time - the point of using functions for this is so that you can change the values and they'll still work. Hardcoding speed values breaks that.
Good catch on that first thing, my gravity is 0.5 so that should've been greater -0.5. I should also probably flip those to so gravity is applied first.





I did explain in detail why direction works that way

My code is written in such a way that hspd is always a positive number and it's direction is decided by multiplying hspd*hdir to return correct movement direction. This also allows me to do moving platforms by giving the solid floor parent object it's own hspd of 0 that the player checks for and adds that can be overwritten to a higher value in moving platform children to make the player move with them.


Left and Right keys

GML:
    if keyboard_check (vk_right) {

        if hdir == -1{
        hspd = 0;
        }
    
        if hspd < 4{
        hspd += 0.075;}

    image_speed = 0.2;
    sprite_index = Sarah_Right_Spr;
    hdir = 1;
    alarm[1] = 5*global.game_speed;
    idle_phase = 0;
    }

   else if keyboard_check (vk_left) {

        if hspd < 4{
        hspd += 0.075;}
    
    image_speed = 0.2;
    sprite_index = Sarah_Left_Spr;
    hdir = -1;
    alarm[1] = 5*global.game_speed;
    idle_phase = 0;
    }




Final code to apply hspd including block to check the current platforms hspd

GML:
//check to see if platform is moving
if place_meeting (x, y+1, Solid_Floor_Obj) {

    var platform_id = instance_place(x,y+1, Solid_Floor_Obj);

    platform_spd = platform_id.hspd*platform_id.hdir;
}

//apply horizontal movement
x += platform_spd +(hspd*hdir);

hdir is also used in setting sprites in several places
 
Last edited:

Mk.2

Member
It still doesn't seem like hdir is necessary in your movement and collision code. Why do you need it for moving platforms? Here's some moving platform code I just wrote.

Player's step event:
GML:
var inst = instance_place(x,y+1,obj_movingPlatform);
if (inst != noone)
{
    movingPlatformHspd = inst.hspd;
}
else movingPlatformHspd = 0;
In obj_movingPlatform's step event, the x coordinate is updated every frame using hspd. After a timer counts down (you could use distance instead), hspd is multiplied by -1, reversing the direction, and the timer is reset. The player object then adds movingPlatformHspd to its own hspd when updating the x coordinate. In both objects, the movement direction is down to whether hspd is positive or negative, there is no need for a seperate variable for this purpose.
 
Last edited:
Because once again it's coded in such a way that hspd values are always positive so they need to be converted to the correct direction with hspd*hdir. This is because it's proved to be simpler in a lot of instances than ensuring the game is correctly applying positive and negative values to the hspd directly.

And the way my code is setup moving platforms can just be child objects of the solid floor parent so I don't have to check several different objects for gravity and I can add more types of moving platforms without adding new blocks of code for each one since it's just checking universally for the floors hspd and direction.
 
Last edited:

Mk.2

Member
Because once again it's coded in such a way that hspd values are always positive so they need to be converted to the correct direction with hspd*hdir.
Yes, if I had missed that then I wouldn't have asked why you're doing it that way. Why do you require that hspd values are always positive? Can you explain why the following code would not work for you?

GML:
//Movement
if (keyboard_check(vk_right))
{
    if hdir == -1{
    hspd = 0;
    }

    if abs(hspd) < 4{
    hspd += 0.075;}

    hdir = 1;
    //Sprite code etc.
}

if (keyboard_check(vk_left))
{
    if abs(hspd) < 4{
    hspd -= 0.075;}

    hdir = -1;
    //Sprite code etc.
}

//Moving platforms
var inst = instance_place(x,y+1,Solid_Floor_Obj);
if (inst != noone)
{
    movingPlatformHspd = inst.hspd;
    movingPlatformVspd = inst.vspd;
}
else
{
    movingPlatformHspd = 0;
    movingPlatformVspd = 0;
}

//Collisions
if place_meeting(x+hspd,y,Solid_Floor_Obj)
{
    while !place_meeting(x+sign(hspd),y,Solid_Floor_Obj)
    {
        x += sign(hspd);
    }

    hspd = 0;
}

x += hspd + movingPlatformHspd;

if place_meeting(x,y+vspd,Solid_Floor_Obj)
{
    while !place_meeting(x,y+sign(vspd),Solid_Floor_Obj)
    {
        y += sign(vspd);
    }

    vspd = 0;
}

y += vspd + movingPlatformVspd;

Note the use of the abs function, would this be useful for you in those instances you mentioned where keeping hspd positive makes things simpler?
 
Last edited:
At this point I think we're really just arguing about personal preference in methodology because both ways work with the error fixed

I am overhauling the code to use lerp now and changing how the hspd is applied either way so it's a moot disagreement
 
Last edited:
Top