GML Pixel-Perfect Object-based Collision

Discussion in 'Tutorials' started by CardinalCoder64, Jul 20, 2017.

  1. CardinalCoder64

    CardinalCoder64 Member

    Joined:
    May 19, 2017
    Posts:
    101
    GM Version: All
    Target Platform: All
    Downloads: (Towards bottom of post)

    Summary:
    This post is for anyone who needs help with collision checking when it comes to pixel- and subpixel-perfect accuracy. This isn't grid collision but I feel it is a more efficient way of implementing object-based collisions.

    Tutorial:
    So I guess it's safe to assume that nearly any game dev using GM is familiar with how object-based collisions are commonly handled...

    Code:
    //Horizontal collisions
    if place_meeting(x+hspd,y,obj_wall) {
            while !place_meeting(x+sign(hspd),y,obj_wall) {
                     x += sign(hspd);
            }
            hspd = 0;
    }
    x += hspd;
    ...then check for vertical collisions the same way.

    This is all fine and dandy and certainly is a way to check for collisions. However, when working with a low-res project (very low, like 144x112) or even prototypes, you will begin to notice that if the player is moving at subpixel increments (so like if it's movespeed contains a decimal), the player is just a tad bit over/under the platform he is colliding with. While this collision checking system works, it isn't exactly pixel-perfect.

    The player is an 8x8 blue square. I set the player's movespeed to 2.9. If you look close enough, you can see that he goes a little bit over the wall on the left and actually never touches the wall on the bottom...
    [​IMG]

    So how can we fix this? Well rather than checking from the player's speed, we check from the player's location. If you are familiar with how tile-based collisions work, then you should understand what I mean by this. (To put it simply, tile-based collisions work using a grid system. If the player runs into a tile, snap him back to the grid. I recommend doing some research on how tile-based collision checking works if you are having trouble understanding.) We use the player's collision mask directly to determine whether or not we're about to collide with the wall (because you know, it's a collision mask).

    First, we need to get the player's bounding box sides based on his origin. To do this, simply...

    Code:
    //Offsets
    var sprite_bbox_top = sprite_get_bbox_top(sprite_index) - sprite_get_yoffset(sprite_index);
    If you've ever seen @GMWolf's video on GM2 tile-collisions, then this should look familiar. This will tell us how far the player's bbox_top is from the origin and will be useful to re-aligning the player later on. Now we do this for the other 3 sides: bottom, left, and right, using sprite_get_xoffset for both left and right.

    NOTE: If the collision mask is not the same as the sprite's (say the player has animations and is using another sprite as a consistent collision mask), switch sprite_index to mask_index that way the mask isn't changing between each animation (or change the collision mask in the object editor, whichever works)

    So now that we've got our sprite info, it's time to put it to good use. We'll start with horizontal collisions first...

    Code:
    //Horizontal collisions
    x += hspd;
    
    //Snap
    if place_meeting(x+sign(hspd),y,obj_wall) {
        var wall = instance_place(x+sign(hspd),y,obj_wall);
        if hspd > 0 { //right
            x = (wall.bbox_left-1)-sprite_bbox_right;
        } else if hspd < 0 { //left
            x = (wall.bbox_right+1)-sprite_bbox_left;
        }
        hspd = 0;
    }
    Now I know this may seem complicated at first glance, but logically it isn't. First, we check to see if there is a wall 1 pixel in front of us in relation to our hspd. We then get the id of the wall we're about to collide with, and snap the player in relation to the wall, so if we're moving right and we hit a wall from our right, we use the bbox_left from the wall (minus 1 because we don't want to be exactly where the wall's bbox_left is, we want to be next to it.), subtract it from the player's right offset, then set the player's hspd to 0. Then we do the same vertically. This way the player isn't over/under the wall anymore; the player is exactly where he needs to be. This is pixel-perfect.

    Now the player is touching both walls without going over them or ever touching them at all. The player's movespeed is still 2.9.
    [​IMG]

    Really that's all there is to it. Cram all this into a script and it should be good to go!

    NOTE: This tutorial does NOT take diagonal collisions into account currently, but I will update the thread once I can implement it.

    If anyone needs a more "hands-on" example, I created a project to demonstrate*:
    GM2: https://drive.google.com/open?id=0B5Yl_iO_QkgZNklac0UyRllIRHc
    GM:S/1.4: https://drive.google.com/open?id=0B5Yl_iO_QkgZWGNFZWxLdl9oQ2c

    Links: N/A

    *press [SPACE] to switch between collision checking systems
     
    Last edited: Sep 20, 2018
    Sozidar, Director_X, Japster and 13 others like this.
  2. Gai Daigoji

    Gai Daigoji Member

    Joined:
    Jun 21, 2016
    Posts:
    11
    Thanks for this!
     
    CardinalCoder64 likes this.
  3. Snayff

    Snayff Member

    Joined:
    Jul 18, 2017
    Posts:
    213
    Thanks for sharing this.

    Please forgive my ignorance but what is the benefit of using code for collision checking over the collision event?
     
  4. CardinalCoder64

    CardinalCoder64 Member

    Joined:
    May 19, 2017
    Posts:
    101
    Ignorance forgiven. :p

    The collision event only triggers when two collision masks meet. When using code for collision checking in the step event, it's triggered every frame. It's better to check for collisions before actually colliding with something so that the player has a better idea of when to stop moving. At least, this is the logic behind using the commonly coded collision system. My optimized collision system simply relocates the player when a collision does happen, but since we have to check the player's hspd beforehand, it must be coded in. That and using code is (generally) more faster & efficient overall. You have more control over using code than you do using events, given the situation.
     
    Last edited: Mar 14, 2018
  5. Snayff

    Snayff Member

    Joined:
    Jul 18, 2017
    Posts:
    213
    Haha thanks, and thanks for coming back to me mate.

    All things being equal, does that axiom hold for all events? I.e. at a certain point do you believe it is worth shifting the work on to custom functions?

    At my current stage of GML infancy I think sticking with the native events makes sense but I expect as I progress I will run in to these hurdles so it is good to know about these things ahead of time!

    P.s. the GIFs really helped clarify! the extra effort in including them is definitely appreciated!
     
    Brandiin and CardinalCoder64 like this.
  6. CardinalCoder64

    CardinalCoder64 Member

    Joined:
    May 19, 2017
    Posts:
    101
    Indeed I do, but it's whatever works for you. I personally have never used the D&D system so I can't say GML is better, but hey if it works it works. When using GML though, you have more control over how and when things should happen based on what your game requires. Working with GML takes some getting used to at first, but it becomes easier with experience. I've reached a point where it feels "unnatural" to not work with code because I've grown so attached to it. I definitely recommend diving into GML a little more so you can have a better understanding of how everything works in GM and better understand why something isn't working right from a logical standpoint and attempt to fix it. I'm not saying you can't accomplish this with D&D, but with GML it's more "system-integrated" if that makes any sense.

    Your welcome! ;)
     
  7. Edmanbosch

    Edmanbosch Member

    Joined:
    Jan 6, 2017
    Posts:
    180
    Pretty good, nice tutorial. Your code is a bit messy though. Also, would it be better to put the snap code inside the actual wall collision?
     
  8. CardinalCoder64

    CardinalCoder64 Member

    Joined:
    May 19, 2017
    Posts:
    101
    I'm afraid not, since we must check ahead of the player before the collision, rather than when a collision is triggered. We're not relocating the player when we collide, but before we collide.
     
    Japster likes this.
  9. Edmanbosch

    Edmanbosch Member

    Joined:
    Jan 6, 2017
    Posts:
    180
    I've tried putting it in the collision code, and it works just fine. I'm still not sure what the problem of doing this is?
     
  10. CardinalCoder64

    CardinalCoder64 Member

    Joined:
    May 19, 2017
    Posts:
    101
    How did you go about doing it exactly? Did you mean making a collision event with the wall inside the player? I tried doing that and it doesn't seem to be working for me. Perhaps you left the code in collide_2()?
     
  11. Edmanbosch

    Edmanbosch Member

    Joined:
    Jan 6, 2017
    Posts:
    180
    This was how I did it:
    Code:
    if (place_meeting(x + hsp, y, obj_wall)) {
        while (!place_meeting(x + sign(hsp), y, obj_wall)) {
            x += sign(hsp);
        }
     
        _wall = instance_place(x + sign(hsp), y, obj_wall);
        if (hsp > 0) {
            x = (_wall.bbox_left - 1) - _sprite_bbox_right;
            hsp = 0;
        }
        else {
            x = (_wall.bbox_right + 1) - _sprite_bbox_left;
            hsp = 0;
        }
     
        hsp = 0;
    }
    x += hsp;
    And I did the same for the vertical collision.
     
  12. CardinalCoder64

    CardinalCoder64 Member

    Joined:
    May 19, 2017
    Posts:
    101
    Oookay I see what you did there, and hey that's one way to do it. To me it seems like extra work though, but I admit it is a bit easier to read than what I came up with.
     
  13. Edmanbosch

    Edmanbosch Member

    Joined:
    Jan 6, 2017
    Posts:
    180
    How is it extra work?
     
  14. CardinalCoder64

    CardinalCoder64 Member

    Joined:
    May 19, 2017
    Posts:
    101
    I don't find it necessary to combine both collision systems honestly. I can see that one could work as a fail-safe for the other, but what I had looked at when I said it is when I saw this code:
    It's redundant to inch closer to the wall when the player is going to be relocated by the code that comes after it anyways, and hsp is already going to be 0 if we are next to the wall, so there's no need to set it to 0 at the end. Also, I keep getting this error:
    ___________________________________________
    ############################################################################################
    FATAL ERROR in
    action number 1
    of Step Event0
    for object Player:

    Variable <unknown_object>.bbox_right(21, -2147483648) not set before reading it.
    at gml_Script_collide_2 (line 19) - x = (wall.bbox_right + 1) - sprite_bbox_left;
    ############################################################################################
    --------------------------------------------------------------------------------------------
    stack frame is
    gml_Script_collide_2 (line 19)
    called from - gml_Object_Player_Step_0 (line 17) - collide_2();
    What I believe is happening here is var "wall" is being set when the player detects a wall "hspd" pixels in front of them. Since var "wall" = instance_place(x+sign(hspd),y,obj_wall), the player detects a wall, but "wall" doesn't. This leads to the code trying to find the bbox_right of an object that isn't detected yet. Am I the only one getting this error?

    Regardless, here's what I believe to be a better solution (and I'll update the thread after this post):
    Code:
    //Horizontal collisions
    x += hspd;
    if place_meeting(x+sign(hspd),y,Solid) {
        var wall = instance_place(x+sign(hspd),y,Solid);
        if hspd > 0 { //right
            x = (wall.bbox_left-1)-sprite_bbox_right;
        } else { //left
            x = (wall.bbox_right+1)-sprite_bbox_left;
        }
        hspd = 0;
    }
    ...and the same vertically.
     
    Last edited: Jul 25, 2017
  15. Edmanbosch

    Edmanbosch Member

    Joined:
    Jan 6, 2017
    Posts:
    180
    I prefer checking to see if the player is about to hit a wall and add hsp to the x after collisions(same for vertical), but yours works too.
     
  16. CardinalCoder64

    CardinalCoder64 Member

    Joined:
    May 19, 2017
    Posts:
    101
    Hey man whatever works for you. ;)
     
    Edmanbosch likes this.
  17. Snayff

    Snayff Member

    Joined:
    Jul 18, 2017
    Posts:
    213
    So I am using GML. I haven't used dnd at all. I am using a collision event and then putting the code in there. Am I right in thinking that your suggested method would be to create your own script to check for collision? Which presumably would be stored in a step event?
     
  18. CardinalCoder64

    CardinalCoder64 Member

    Joined:
    May 19, 2017
    Posts:
    101
    That'd be the way to do it! If the code is put into a script, it helps keep things organized and can be sometimes easier to debug (because you'll be able to find bugs faster when errors do occur.)

    And yes, we want this in the step event because in addition to collision checking, we are also moving the player per frame, as suggested by the code "x+=hspd" and "y+=vspd" (and also because we can't really put it anywhere else in all honesty).
     
    Japster likes this.
  19. Snayff

    Snayff Member

    Joined:
    Jul 18, 2017
    Posts:
    213
    Got you buddy, thank you. I look forward to trying it out.
     
    CardinalCoder64 likes this.
  20. Snayff

    Snayff Member

    Joined:
    Jul 18, 2017
    Posts:
    213
    I am trying to implement this but I am being dense... what is the Solid variable being looked for? Does it require the "solid" option to be ticked on walls?

    Edit:
    Changed it to look for the parent of my walls and it seems to work! Need to test properly but looking good, thanks buddy!
     
    Last edited: Jul 28, 2017
  21. MightyJo

    MightyJo Guest

    Mate you might just wanna change this:
    Code:
    var sprite_bbox_top = sprite_get_bbox_top(sprite_index) - sprite_get_yoffset(sprite_index);
    
    And instead of using sprite_index tell the reader to use his mask image.

    Some of us use animations, and using sprite_index there, makes my player spaz like there's no tomorrow. It gave me quite a few head scratches before I figured out what was going on. Otherwise brilliant code my friend. Kisses and smooches all around.
     
    Japster and CardinalCoder64 like this.
  22. CardinalCoder64

    CardinalCoder64 Member

    Joined:
    May 19, 2017
    Posts:
    101
    Like how so? Is your collision mask changing between animations or does it remain that same throughout?
     
  23. MightyJo

    MightyJo Guest

    The mask is always the same. Your code gets the boundaries of the current sprite that is shown, not the boundaries of the mask. The sprite of the player is ever changing in width:

    [​IMG]

    When my player is in that state and tries to collide with the wall he starts spazzing in front of it (also, just so you know, the animation is set to play only when x is either > or < than xprevious and to show a static sprite when they are =). Or maybe the problem is that the player's mask is one pixel smaller on each side (left and right) that the smallest animation sprite:

    [​IMG]

    But I don't think that's the problem since your code only takes into account sprite boundaries, I think, right? But regardless of what the issue really is, changing sprite_index to mask_index solved the problem.
     
    Last edited by a moderator: Jul 31, 2017
  24. CardinalCoder64

    CardinalCoder64 Member

    Joined:
    May 19, 2017
    Posts:
    101
    The sprite_get_bbox functions get the bounding box sides relative to (0,0) of the sprite index. They take into account mask boundaries, obtained from the sprite itself. One thing to note is that these values are taken from the collision mask properties window of the sprite editor...
    [​IMG]
    So according to this, sprite_get_bbox_top would return 0 here. If you're using a separate sprite as a collision box, maybe try replacing sprite_index with the index of the collision sprite? I replaced sprite_index with mask_index like you said and the player keeps going into the wall. That's an interesting error though...because I'm using this same collision system in another project that uses animations as well and I've never gotten this error. But hey if it works for you, it should be okay I guess.
     
  25. Ceddil

    Ceddil Member

    Joined:
    Aug 1, 2017
    Posts:
    26
    I tried this and it jumps through the wall when going at it from the top or bottom. could you help?
    Code:
    //bbox variables
    var sprite_bbox_top = sprite_get_bbox_top(sprite_index) - sprite_get_yoffset(sprite_index);
    var sprite_bbox_left = sprite_get_bbox_left(sprite_index) - sprite_get_xoffset(sprite_index);
    var sprite_bbox_right = sprite_get_bbox_right(sprite_index) - sprite_get_xoffset(sprite_index);
    var sprite_bbox_bottom = sprite_get_bbox_bottom(sprite_index) - sprite_get_yoffset(sprite_index);
    
    //Horizontal collisions
    x += hspd;
    
    //Snap
    if place_meeting(x+sign(hspd),y,obj_solid) {
        var wall = instance_place(x+sign(hspd),y,obj_solid);
        if hspd > 0 { //right
            x = (wall.bbox_left-1)-sprite_bbox_right;
        } else { //left
            x = (wall.bbox_right+1)-sprite_bbox_left;
        }
        hspd = 0;
    }
    
    //vertical collisions
    y += vspd;
    
    //Snap
    if place_meeting(x,y+sign(vspd),obj_solid) {
        var wall = instance_place(x,y+sign(vspd),obj_solid);
        if vspd > 0 { //top
            y = (wall.bbox_top-1)-sprite_bbox_top;
        } else { //bottom
            y = (wall.bbox_top+1)-sprite_bbox_bottom;
        }
        vspd = 0;
    }
    [CODE]
     
    Last edited: Aug 1, 2017
  26. CardinalCoder64

    CardinalCoder64 Member

    Joined:
    May 19, 2017
    Posts:
    101
    When vspd > 0 (meaning you're going down), you should be subtracting by sprite_bbox_bottom instead of sprite_bbox_top, because the bottom of the player should meet the top of the wall. As for when vspd < 0 (going up), it should be the same logic: The top of the player should be colliding with the bottom of the wall. It's important to not understand how something isn't working, but why it isn't. Doing so can strengthen your efficiency as a programmer so you can fix these kinds of errors on your own later on. Hope you got something out of this!
     
    Last edited: Aug 1, 2017
  27. Ceddil

    Ceddil Member

    Joined:
    Aug 1, 2017
    Posts:
    26
    i understand why it isnt working, but i cant fix it. I dont know what i am doing wrong here. I re-wrote the code and it is working a little better, but i still need some help
    Code:
    //vertical collisions
    y += vspd;
    
    //Snap
    if place_meeting(x,y+sign(vspd),obj_solid) {
        var wall = instance_place(x,y+sign(vspd),obj_solid);
        if vspd > 0 { //top
            y = (wall.bbox_top+1)-sprite_bbox_bottom;
        } else { //bottom
            y = (wall.bbox_bottom-1)-sprite_bbox_top;
        }
        vspd = 0;
    }
    this is in the step event of the player, and when i collide vertically it pushes me all he way to the right.
     
  28. CardinalCoder64

    CardinalCoder64 Member

    Joined:
    May 19, 2017
    Posts:
    101
    Because you're putting the player inside the wall. Next to wall.bbox_top and wall.bbox_bottom, flip the signs. It should be (wall.bbox_top-1), because we want to be a pixel above the top. Another thing to note is in GameMaker (or any other display for that matter), coordinate (0,0) is at the top left, not the bottom left like a standard graph. So if we go up, we are decreasing in y, but if we go down, we are increasing. It's weird, but that's just how it is.

    So it would be (wall.bbox_top-1) and (wall.bbox_bottom+1).
     
  29. Ceddil

    Ceddil Member

    Joined:
    Aug 1, 2017
    Posts:
    26
    i did exactly what you said, and i dont know if i'm just bad at coding or math, but it didnt change anything.
    Code:
    //vertical collisions
    y += vspd;
    
    //Snap
    if place_meeting(x,y+sign(vspd),obj_solid) {
        var wall = instance_place(x,y+sign(vspd),obj_solid);
        if vspd > 0 { //top
            y = (wall.bbox_top-1)-sprite_bbox_bottom;
        } else { //bottom
            y = (wall.bbox_bottom+1)-sprite_bbox_top;
        }
        vspd = 0;
    }
    and if this is the problem, here is the bounding box variables
    Code:
    //bbox variables
    var sprite_bbox_top = sprite_get_bbox_top(sprite_index) - sprite_get_yoffset(sprite_index);
    var sprite_bbox_left = sprite_get_bbox_left(sprite_index) - sprite_get_xoffset(sprite_index);
    var sprite_bbox_right = sprite_get_bbox_right(sprite_index) - sprite_get_xoffset(sprite_index);
    var sprite_bbox_bottom = sprite_get_bbox_bottom(sprite_index) - sprite_get_yoffset(sprite_index);
     
  30. CardinalCoder64

    CardinalCoder64 Member

    Joined:
    May 19, 2017
    Posts:
    101
    You didn't change your horizontal collisions at all? The vertical collisions are right as well as the bounding boxes, so it should be functional. If nothing else works, try switching "sprite_index" to "mask_index" in the bounding box vars. This seemed to work for @MightyJo so it may work for you. Also be sure your player has a mask as well as your walls.
     
  31. Mister10

    Mister10 Member

    Joined:
    Jan 22, 2017
    Posts:
    38
    hi, I tried the code, and my character just falls through the floor. I used the whole mask index thing and it didn't fix it.
    here's my code. I don't know if I'm doing anything wrong.

    //bbox
    var sprite_bbox_top = sprite_get_bbox_top(mask_index) - sprite_get_yoffset(mask_index);
    var sprite_bbox_left = sprite_get_bbox_top(mask_index) - sprite_get_xoffset(mask_index);
    var sprite_bbox_right = sprite_get_bbox_top(mask_index) - sprite_get_xoffset(mask_index);
    var sprite_bbox_bottom = sprite_get_bbox_top(mask_index) - sprite_get_yoffset(mask_index);

    //Horizontal collisions
    x += hsp;

    //Snap
    if place_meeting(x+sign(hsp),y,obj_block) {
    var wall = instance_place(x+sign(hsp),y,obj_block);
    if hsp > 0 { //right
    x = (wall.bbox_left-1)-sprite_bbox_right;
    } else { //left
    x = (wall.bbox_right+1)-sprite_bbox_left;
    }
    hsp = 0;
    }
    //Vertical collisions
    y += vsp;

    //Snap
    if place_meeting(x,y+sign(vsp),obj_block) {
    var wall = instance_place(x,y+sign(vsp),obj_block);
    if vsp > 0 { //right
    y = (wall.bbox_top-1)-sprite_bbox_bottom;
    } else { //left
    y = (wall.bbox_bottom+1)-sprite_bbox_top;
    }
    vsp = 0;
    }
     
  32. Bentley

    Bentley Member

    Joined:
    Jun 18, 2017
    Posts:
    800
    Thanks for the tutorial, it was very helpful. Thumbs up!

    I just had a quick question.
    Why do you recommend a centered origin as the code works for any origin (correct me if I'm wrong).
     
  33. Christopher Rosa

    Christopher Rosa Member

    Joined:
    Dec 8, 2016
    Posts:
    34
    I put all of the code in the step event of my player but when I land on obj_floor I glitch inside of it and start moving really fast to the right until there isnt any floor and then just fall.
     
  34. ridiculoid

    ridiculoid Member

    Joined:
    Mar 29, 2018
    Posts:
    3
    For anybody having trouble with this. There's a bug in this code. You need to change the "else" statements to "else if" statements. The "else" statements will trigger when the vspd or hspd is == 0. You're not going to want that. So instead of "else { //left", it needs to be "else if hsp < 0 { //left"
     
  35. NeZvers

    NeZvers Member

    Joined:
    Mar 24, 2018
    Posts:
    320
    Lovely tutorial. I was frustrated with traditional collision system myself and this is similar to one of my collision test systems, only bit better.
    I feel that this is a bit better way to do since you don't need loop to do counting.
     
  36. NeZvers

    NeZvers Member

    Joined:
    Mar 24, 2018
    Posts:
    320
    Ok, I got time to revise my game code and I wanted to implement this collision system aaaand with that I found some improvements.
    Since I don't like incomplete code shown, I'll lay it down so newcomers couldn't mess it up.
    First thing - since I use same collision mask for all animations I SET IT AND FORGET IT in create event:

    Code:
    ///Create_event
    
    //I think this is better calculation for single mask
    sprite_bbox_top = bbox_top - y;
    sprite_bbox_bottom = bbox_bottom - y;
    sprite_bbox_right = bbox_right - x;
    sprite_bbox_left = bbox_left - x;
    
    Code:
    //Horizontal collisions
    x += hspd;
    
    //Snap
    if place_meeting(x, y, oSolid) { // DON'T USE sign(hspd) since you are checking current possition
        var wall = instance_place(x+sign(hspd),y,oSolid); // same thing you are inside and don't want to check 1px more
        if (hspd > 0) { //right
            x = (wall.bbox_left-1)-sprite_bbox_right;
        } else if (hspd < 0) { // <<------ as it was pointed out need to have else if otherwise hspd=0 is included
            x = (wall.bbox_right+1)-sprite_bbox_left;
        }
        hspd = 0;
    }
    
    //Vertical collisions
    y += vspd;
    
    //Snap
    if place_meeting(x, y, oSolid) {
        var wall = instance_place(x, y, oSolid);
        if (vspd > 0) { //down
            y = (wall.bbox_top-1) - sprite_bbox_bottom;
        } else if (vspd < 0) { //up
            y = (wall.bbox_bottom+1) - sprite_bbox_top;
        }
        vspd = 0;
    }
    
    This is now my go-to collision system because it survived vertically moving platforms spectacularly.
     
    Last edited: Oct 10, 2018
  37. CardinalCoder64

    CardinalCoder64 Member

    Joined:
    May 19, 2017
    Posts:
    101
    Woah this thread has gotten a lot of views! Much appreciation to those who have found bugs in the code, and I'll update the thread along with those fixes as well as the aforementioned diagonal capabilities. Also a few things:
    I guess it shouldn't matter too much, but I found it to be less buggy that way. It's a habit of mine that sorta bled through the thread so I apologize if this caused any confusion.
    Thanks for this, I'll update the thread!
    Bit of an old quote but this is true. Didn't find the bug out myself until just recently, so expect an update!
     
    Bentley likes this.
  38. CarlFoReal

    CarlFoReal Member

    Joined:
    Oct 9, 2018
    Posts:
    1
    I used this code and got an error saying the vspd was not set prior to reading it. chances are I'm just missing a variable but who knows. Any help would be appreciated given I've got minimal experience coding and collisions are the current problem. Thanks in advance.
     
  39. NeZvers

    NeZvers Member

    Joined:
    Mar 24, 2018
    Posts:
    320
  40. Jumper

    Jumper Member

    Joined:
    Jan 10, 2019
    Posts:
    2
    This code is awesome, works great for moving platforms. But my guy starts teleporting all over the place if he collides both horisontal and vertically. Is there any good workaround for that?

    And to OP: Why do you (and nearly everyone else) post half the code and "Then we do the same vertically", and your demo project is an .exe and not a project file. This was easy enough code but man, everyone does that, its so annoying to spend 20 minutes of plotting and correcting code just to see if it works or not... Thanks for posting everything @NeZvers
     
    NeZvers likes this.
  41. NeZvers

    NeZvers Member

    Joined:
    Mar 24, 2018
    Posts:
    320
    @Jumper You can do whatever you want. You can do additional checks and do collision code if only one side is colliding.
     
  42. DarklinkFighter

    DarklinkFighter Member

    Joined:
    Mar 25, 2018
    Posts:
    26
    Shouldn't this way also include a while loop as well for the case that there are 2 (non player) colliders intersecting each other?

    2019-01-11 14_39_50-Unbenannt - Paint.png

    Without the loop it highly depends on Game Maker which of the Colliders gets detected, and in case it would be the wrong one it would snap the player inside the other one.
    Also the loop would not increase performance to much because these cases are rather rare and only would loop in such cases.

    Or do I understand the snippet wrong?
     
  43. Cedric_of_Maroon

    Cedric_of_Maroon Member

    Joined:
    Aug 31, 2018
    Posts:
    1
    I was able to get pixel-perfect collisions by using the simpler method (judging based on speed rather than snapping) by just rounding the x and y coordinates after the collision every step:

    x = round(x);
    y = round(y);

    Is there any downside to this? Seems to work fine.
     
  44. Destral

    Destral Member

    Joined:
    Jan 21, 2019
    Posts:
    1
    @CardinalCoder64 Did you ever figure out a solution for diagonal movement collision?
     
  45. atmobeat

    atmobeat Member

    Joined:
    Feb 24, 2017
    Posts:
    45
    Ever get around to this? I'd be interested in seeing how you dealt with it.
     
  46. Joe Ellis

    Joe Ellis Member

    Joined:
    Aug 30, 2016
    Posts:
    948
    This is really good, and I hope people see this and think its the normal way to do it, rather than the stupid while loop,
    The bbox vars are underrated, most simple collisions can be done with these and pretty much every old 2d game used to work like this.

    You need to learn about vectors for the diagonal collisions though, there's quite a few simple things you can do which make the objects slide along lines perfectly. Learn about vertices, edge vectors between 2 vertices, cross products & dot products
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice