GMS 2.3+ Gravity Code Problem

I'm at a solid brick wall here and not sure what to do

GML:
//set variables for math
var B_Y = (sprite_height)+vspd;
var T_Y = y+vspd;
var R_X = sprite_width-5;


//find floor and land on it 
if collision_line(x+2, y+B_Y, x+R_X, y+B_Y, Solid_Floor_Obj, false, true){
    
    while !collision_line(x+5, y+B_Y, x+R_X, y+sprite_height, Solid_Floor_Obj, false, true){
    y += sign(vspd);     
    }

vspd = 0;
}

NOTHING in this code is working right with the debugger showing that the while loop is never actually triggering. This results in tons of intended behavior that ranges from the objecting it using stuck in the sky or half way into the floor, as you can see in this screenshot of a test room I've been playing around in.

I've been sitting here like two hours staring at the debugger and checking various numbers while changing small things but I can find no cause for or solution to the problem. I'm tapped out.
 

Attachments

rytan451

Member
You're checking if there's a floor below the object. If there's no floor, then the object doesn't go down. Are you missing an else case?
 

Roldy

Member
Assuming the origin of you sprite y is at the top. Then y+sprite_height would be the bottom.

GML:
var B_Y = (sprite_height)+vspd;
var T_Y = y+vspd;
var R_X = sprite_width-5;

// If this returns true then we know there is a collision at  'y+B_Y'
if collision_line(x+2, y+B_Y, x+R_X, y+B_Y, Solid_Floor_Obj, false, true){

    // Since we know there is a collision at y+B_Y then this 'while' condition will also return true
    // but you are negating it with '!' so its value is FALSE
    // The While loop never happens.
    while !collision_line(x+5, y+B_Y, x+R_X, y+sprite_height, Solid_Floor_Obj, false, true){
    y += sign(vspd);
    }

vspd = 0;
}
Instead of starting at y+B_Y start at y+sprite_height (the bottom of the sprite). Then the while loop increments y until the bottom of the sprite hits the floor.

GML:
    // Check if bottom of sprite does not collide with floor
    while !collision_line(x+5, y+sprite_height, x+R_X, y+sprite_height, Solid_Floor_Obj, false, true){
        // Increase y 1 at a time towards the floor (assuming vspd is positive)
        y += sign(vspd);
    }
 
Last edited:
You're checking if there's a floor below the object. If there's no floor, then the object doesn't go down. Are you missing an else case?
The exclamation point before the function means "if condition is NOT true".

Assuming the origin of you sprite y is at the top. Then y+sprite_height would be the bottom.

GML:
var B_Y = (sprite_height)+vspd;
var T_Y = y+vspd;
var R_X = sprite_width-5;

// If this returns true then we know there is a collision at  'y+B_Y'
if collision_line(x+2, y+B_Y, x+R_X, y+B_Y, Solid_Floor_Obj, false, true){

    // Since we know there is a collision at y+B_Y then this will also return true
    // but you are negating it with '!' so its value is FALSE
    // The While loop never happens.
    while !collision_line(x+5, y+B_Y, x+R_X, y+sprite_height, Solid_Floor_Obj, false, true){
    y += sign(vspd);
    }

vspd = 0;
}
Instead of starting at y+B_Y start at y+sprite_height (the bottom of the sprite). Then the while loop increments y until the bottom of the sprite hits the floor.

GML:
    // Check if bottom of sprite collides with floor
    while !collision_line(x+5, y+sprite_height, x+R_X, y+sprite_height, Solid_Floor_Obj, false, true){
        // Increase y 1 at a time (assuming vspd is positive)
        y += sign(vspd);
    }
The exclamation point before the function means "if condition is NOT true".
When I boot GMS back up tomorrow I'll have to try that change and see if it fixes anything
 
There's no exclamation point. It doesn't reach the while statement if there's nothing below.
It's checking to see if the player will hit the floor in the next step, and then if they will setting vspd to zero and easing them down into place with the while loop.

I'm not entirely sure how you're reading to code to think it does the reverse of stopping if there's no floor.
 

Mk.2

Member
GML:
    while !collision_line(x+5, y+B_Y, x+R_X, y+sprite_height, Solid_Floor_Obj, false, true){
Look at the coordinates you've used here and visualize what that line would look like. I realize that Roldy already answered this, but your reply suggested some uncertainty about it being the solution.
 
Last edited:

rytan451

Member
I'm not entirely sure how you're reading to code to think it does the reverse of stopping if there's no floor.
Well, if the line isn't reaching the floor, then there doesn't seem to be any code that makes the object go down. A simple else y += vspd; might fix the problem if that's the case.
 
Look at the coordinates you've used here and visualize what that line would look like. I realize that Roldy already answered this, but your reply suggested some uncertainty about it being the solution.
I know it probably likely is but this block of code has been whooping up on my ass so long I have a certain level of doubt built up in anything actually working until it actually does.
 

Nidoking

Member
Here's a picture. Your first check is what's on the left - you're checking for a floor below the sprite, where it's going to land. The second check SHOULD be the bottom row of pixels in the sprite, but you wrote it to do what's on the right. If you're going to question people giving you answers, why are you posting the questions here?
 

Attachments

Here's a picture. Your first check is what's on the left - you're checking for a floor below the sprite, where it's going to land. The second check SHOULD be the bottom row of pixels in the sprite, but you wrote it to do what's on the right. If you're going to question people giving you answers, why are you posting the questions here?
I didn't question anyone?

There's honestly zero need to get hostile like that.
 
If you can't look at what you've done, look at what people are telling you is wrong, and see the problem for yourself, especially with a picture, then you may have more inherent problems than not understanding logic. Could be dyslexia or another reading disorder. If you're aware of it already, then I'm not telling you anything new, but if that's news to you, it could be worth taking up with a doctor. You can still accomplish great things, but there are techniques to help you compensate for your issues that you could benefit from.
Okay, wow.

1)That's just plain crossing line of civil forum conduct

2)I was referring to that person in particular misreading the code as intending to do something it didn't do, not the other two posters who pointed out an error and are 100% correct about it.

3)The second one was a joke
 

TsukaYuriko

☄️
Forum Staff
Moderator
Let's focus less on ass-whooping each other and more on the ass-whooping code? :)

One thing I find incredibly helpful when dealing with any kind of collision check is to visualize the collision hitbox. As in, if you have a line collision, draw a line that mimics the parameters of the collision check. That'll show you what's checking for collisions where, and whether that's what you intended to do. Maybe that will provide some insight into what's going wrong.
 
Seriously though

I really do think it's the thing Roldy and MK found because that's a sizable coding error and before anything else I'll have to try it tomorrow.
 
Okay, the floor phasing was something else entirely I fixed.

Skully is stuck in the air because I'm a moron and wasn't applying the vspd to his person's y value at any point

Now I can get him to fall but I have an entirely different problem where the new collison method doesn't work quite as accurately in placing the player as place_meeting so some stuff that checks for the ground is breaking. So for example I'm finding myself having to check for y+3 instead of y+1.

Yeah, everything seems to be working now but that change in where to check to the ground seems odd
 
Last edited:
Last in this update spam with another, much smaller problem

GML:
//set variables for math
var B_Y = (sprite_height)+vspd;
var T_Y = y+vspd;
var R_X = sprite_width-5;


//find floor and land on it
if collision_line(x+5, y+B_Y, x+R_X, y+B_Y, Solid_Floor_Obj, false, true){
    
    while !collision_line(x+5, y+sprite_height, x+R_X, y+sprite_height, Solid_Floor_Obj, false, true){
    y += sign(vspd);     
    }

vspd = 0;
}
Everything seems to be working save for objects now stop like 3 pixels above the surface instead of resting right on top of it
 

TsukaYuriko

☄️
Forum Staff
Moderator
Is the origin of the instance's sprite at 0,0? Your code relies on this (adding the sprite's height to its y coordinate without taking origins into account). Might want to use bbox_bottom so your code will work regardless of this.
 
Is the origin of the instance's sprite at 0,0? Your code relies on this (adding the sprite's height to its y coordinate without taking origins into account). Might want to use bbox_bottom so your code will work regardless of this.
Yes.

I don't change any of my sprites from the default 0,0 origin because I haven't run into any reason to yet, and with bounding box I can't custom fit the length of the sides to avoid things like the corner of the box touching the floor triggering a false wall collision.
 

Mk.2

Member
I don't change any of my sprites from the default 0,0 origin because I haven't run into any reason to yet
One reason to use a centered x origin would be to simplify dealing with x coordinates. For example, "x + (dist * dir)" instead of requiring a different value for dist depending on dir being 1 or -1.

with bounding box I can't custom fit the length of the sides to avoid things like the corner of the box touching the floor triggering a false wall collision.
bbox_bottom returns the bottom coordinate of the bounding box only, it has nothing to do with the sides of it. You'd use this for the y coordinate in your collision checks, and whatever else you want for the x coordinate.
 
Last edited:
bbox_bottom returns the bottom coordinate of the bounding box only, it has nothing to do with the sides of it. You'd use this for the y coordinate in your collision checks, and whatever else you want for the x coordinate.
Then bbox would be a lot easier that using width/height, wouldn't it?
 

Mk.2

Member
Then bbox would be a lot easier that using width/height, wouldn't it?
Yes, since the origin is irrelevant.

Another thing to consider is your use of sprite_width and sprite_height in your above code, it's more likely that you want the dimensions of the mask_index rather than the current sprite_index. If that's the case, you could use sprite_get_width(mask_index) instead.

Also, are you taking into account that sprite_width and sprite_height are dependant on image_xscale and image_yscale? So for example if you're flipping the sprite's xscale to -1 when facing left, sprite_width will have a negative value. You might be using seperate sprites for left and right instead of flipping them, in which case this won't be an issue. Not relevant to this topic, just something I noticed that may be giving you issues elsewhere.
 
Also, are you taking into account that sprite_width and sprite_height are dependant on image_xscale and image_yscale? So for example if you're flipping the sprite's xscale to -1 when facing left, sprite_width will have a negative value. You might be using seperate sprites for left and right instead of flipping them, in which case this won't be an issue. Not relevant to this topic, just something I noticed that may be giving you issues elsewhere.
I'm actually just using two different sprites made by duplicating the one I actually drew and flipping it in the sprite editor, so no transformations in code going on.
 

Mk.2

Member
The fact that you're not using a centered x origin should've been a clue for me to guess that you're not flipping the sprite via code, but on that note, there's another reason to consider using a centered x origin - no need to duplicate sprites. And if you do go that route, it's better flip it via draw_sprite_ext and a new variable for the xscale argument, rather than changing the built in image_xscale variable.
 
The fact that you're not using a centered x origin should've been a clue for me to guess that you're not flipping the sprite via code, but on that note, there's another reason to consider using a centered x origin - no need to duplicate sprites. And if you do go that route, it's better flip it via draw_sprite_ext and a new variable for the xscale argument, rather than changing the built in image_xscale variable.
Separate sprites was so I can edit the flipped versions and move her wand to the correct hand for consistency later on down the line when engine and demo areas are fully done so I move over to some polish
 
Top