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

Having trouble understanding why my collision code doesn't work properly

Bombeast

Member
I'm attempting to make a platformer game. So far, I have the horizontal movement where I would like it to be; however... I'm having trouble implementing code that properly detects collision. When I move my box, it will stop ever-so briefly before sidling up against the edge. Additionally, occasionally when I land after jumping or falling, I will be stuck in the floor. Jumping allows me to escape, but it will be a full jump and cause my character to simply be plunged into the floor a few pixels again. What am I doing incorrectly here?

GML:
/// @description Things that occur each frame (step)


key_left = keyboard_check(ord("A"));                                                                //Detect "left" key pushed

key_right = keyboard_check(ord("D"));                                                                //Detect "right" key pushed

key_crouch = keyboard_check(ord("S"));                                                                //Detect "down/crouch" key pushed

key_jump = keyboard_check_pressed(vk_space);                                                        //Detect "jump" key pushed


player_facing = key_right - key_left;                                                                //Gives 1 for right, 0 for none or both, -1 for left

player_accelerate = player_facing*h_accel;                                                            //Gives -accel to left and +accel to right


/* Horizontal Movement */


if (key_right || key_left) {                                                                        //If either are pushed...

    

    if (true_speed < walk_speed || true_speed > (walk_speed*-1)) {                                    //If true speed is less than cap...

        true_speed = true_speed + player_accelerate;                                                //Player speed (x movement) will be accelerated appropriately

        

        if (true_speed > walk_speed || true_speed < (walk_speed*-1)) {                                //If player speed is greater or less than max walk speed...

            true_speed = walk_speed*sign(player_facing);                                            //Player speed is set evenly to the max walk speed

        }

    }

}


if (player_facing == 0 && true_speed != 0) {                                                        //If both or none input while player speed is not 0...

    true_speed = true_speed + (-1*(sign(true_speed))*h_accel);                                        //Player speed accel/decelerates until 0


    if ((true_speed > 0 && true_speed < h_accel) || (true_speed < 0 && true_speed > h_accel)) {        //If player speed is greater or less than zero but deceleration over/undershoots...

        true_speed = 0;                                                                                //Set player speed evenly to 0

    }

}


if (!place_meeting(x+true_speed, y, obj_solid)) {

    x = x + true_speed;

} else {

    true_speed = 0;

}


/* Vertical Movement */


if (key_jump && place_meeting(x, y+1, obj_solid)) {

    true_fall = true_fall + jump_height;

}


if (place_meeting(x, y+1, obj_solid)) {

    true_fall = 0;

} else {

    true_fall = true_fall + grav_accel;

}


y = y + true_fall;


/* Reset Room Key */


if (keyboard_check(ord("R"))) {

    room_restart();

}
Let it be known that I deleted the original code for the vertical movement in an attempt to rewrite it correctly, to no avail. So while the original code doesn't exist, I still have problems with it so it doesn't matter. If you'd like to test it out yourself, you can just comment out the vertical movement for now.
 

TheouAegis

Member
You aren't technically stopping before you get to the obstacle, you just aren't moving if there's an obstacle ahead of you. So your problem is your code is telling the object not to even bother moving if there's anything ahead of it and its ever moving faster than one pace over first step. You need to figure out how many pixels you can move before you actually collide with something. One easy way to do this is to check if there will be a collision ahead of you if you move at your desired speed, and then if so move one pixel at a time as long as there is no Collision 1 pixel ahead of you.

Code:
if place_meeting(x+hsp,y,obj_solid) {
    while !place_meeting(x+sign(hsp),y,obj_solid)
        x+=sign(hsp); 
    hsp=0;
}
x += hsp;
 

Spam1985

Member
TheouAegis has supplied the classic go-to movement code that many of us use these days!

It's important to understand how it works though, rather than just copying it and moving on.
I'll try to explain:

In this example, we are firstly checking ahead to see if a collision occurs and if it does:

The while statement continues to loop until the statement is no longer true.
So WHILE there is no collision 1 pixel ahead of us, we move 1 pixel ahead.
The while loop makes this all happen instantly (not 1 pixel per step, but +1 pixel for each loop of the statement)

If you are confused about what "sign" does, it takes any positive number and returns 1. Any negative number returns -1
and 0 just stays at 0. So in this instance we are using it to make those little 1 pixel checks left or right
(depending on the value of hsp)
GML:
//if we have detected a collision ahead of us...
if place_meeting(x + hsp,y, obj_solid) then
{
    //...then as long as we can move 1 pixel ahead, keep doing it!
    while !place_meeting(x + sign(hsp),y ,obj_solid)
    {
        //(these micro movements mean we can move perfectly flush against walls every time)
        x += sign(hsp);
    }
    //... but if we can no longer get 1 pixel closer to the wall then we must stop moving!
    hsp = 0;

}
//now we move, either at our original speed or at 0 speed (depending on if we hit the wall in the check above)
x += hsp;
 

TheouAegis

Member
And I will just put the disclaimer out there: I never said this was the best method, nor even a good method. It's an easy method, one that can be applied to nearly any movement code and doesn't require anything beyond 1st Grade math. Ideally you should be calculating hsp, not relying on fuzzy logic, but that is more difficult to explain to people.
 

Bombeast

Member
Thank you all for your replies, the code works beautifully and I do understand it all. I was able to modify it and make it work for vertical collision too. Hopefully later I can make slopes and such work!
 
Top