• Hey! Guest! The 40th (!!!) GMC Jam will take place between February 25th, 12:00 UTC to March 1st 12:00 UTC. Why not join in this very special anniversary jam! Click here to find out more!

GMS 2.3+ (SOLVED) Collision Detection with Precise Tile Collisions Problem

Mikey3131

Member
Hi all!

Seasoned newbie Mike here. I used Game Maker back when 6 was the latest and greatest and am just now getting back into the swing of game development on Game Maker.

I'm playing around with collisions and saw that tile-based collision detection seems to be a lot more efficient (and faster to map) than object-based collisions. I used the Precise Tile Collisions blog post to implement their solution, but I'm having some collision problems.

Specifically, whenever the player object makes that initial collision, it's stuck in place. It feels like a problem where a pixel is overlapping, and so I'm permanently stuck in place.

I'm sure it's something stupid simple, and I'm just not seeing it.

Here's my current collision code in my player object: (Begin Step phase. tile_meeting_precise completely matches the blog post's code)

GML:
/// @description Insert description here
/// @description Insert description here
// You can write your code in this editor


key_up     = keyboard_check_direct(ord("W"))
key_down = keyboard_check_direct(ord("S"))
key_left    = keyboard_check_direct(ord("A"))
key_right  = keyboard_check_direct(ord("D"))


if (key_up && !tile_meeting_precise(self.x,self.y - self.p_speed,"Tiles_Wall"))
{

    image_speed = i_speed;
    ani_start=12;
    ani_end=15;
    //image_index = 13;
    y -= p_speed;
}

if (key_down) {
    if (!tile_meeting_precise(self.x,self.y + self.p_speed,"Tiles_Wall"))
{
    image_speed = i_speed;
    ani_start=0;
    ani_end=3;
    //image_index = 1;
    y += p_speed;
} //else show_message(string(self.x) + "," + string(self.y + self.p_speed));
}

if (key_left && !tile_meeting_precise(self.x - p_speed,self.y,"Tiles_Wall"))
{
    image_speed = i_speed;
    ani_start=4;
    ani_end=7;
    //image_index = 5;
    x -= p_speed;
}

if (key_right && !tile_meeting_precise(self.x + self.p_speed,self.y,"Tiles_Wall"))
{
    image_speed = i_speed;
    ani_start=8;
    ani_end=11;
    //image_index = 9;
    x += p_speed;
}
}
tile_meeting_precise code:
GML:
function tile_meeting_precise(x,y,layer){
///@description tile_meeting_prcise(x,y,layer)
///@param x
///@param y
///@param layer
var _layer = argument2,
    _tm = layer_tilemap_get_id(_layer);
     _checker = obj_precise_tile_checker;
if(!instance_exists(_checker)) instance_create_depth(0,0,0,_checker);

var _x1 = tilemap_get_cell_x_at_pixel(_tm, bbox_left + (argument0 - x), y),
    _y1 = tilemap_get_cell_y_at_pixel(_tm, x, bbox_top + (argument1 - y)),
    _x2 = tilemap_get_cell_x_at_pixel(_tm, bbox_right + (argument0 - x), y),
    _y2 = tilemap_get_cell_y_at_pixel(_tm, x, bbox_bottom + (argument1 - y));

for(var _x = _x1; _x <= _x2; _x++) {
    for(var _y = _y1; _y <= _y2; _y++) {
        var _tile = tile_get_index(tilemap_get(_tm, _x, _y));
        if(_tile) {
            //if(_tile == 1) {
            //    return true;
            //    }
            _checker.x = _x * tilemap_get_tile_width(_tm);
            _checker.y = _y * tilemap_get_tile_height(_tm);
            _checker.image_index = _tile;

            if(place_meeting(argument0,argument1,_checker)) {
                return true;
                }
        }
    }
}

return false;
}
I appreciate any help and guidance you guys can provide. I'm happy to toss up the .YYZ file for anyone brave enough to peruse through it.

UPDATE:
After doing more digging, it looks like place_meeting is the culprit.


Place_meeting requires BOTH objects to have precision collision turned on, otherwise it treats both objects as bounding box collisions. This is an issue though for player sprites, where they're wider when looking south or north compared to east or west. Ideally, I'd want to check pixel collision on the tileset against the bounding box of the player. I'll do some digging on a work-around and post the solution here.

UPDATE #2:
After reading some articles about the pros and cons of precision collision versus box collision, I opted to go for traditional rectangular collision with tilemaps, using this video as a guide:
 
Last edited:

curato

Member
you can run into issues like that just checking one point. you need to check the four corner and points in the middle until the gap is less than the tile size or your can end up with oddness where your pass through something you shouldn't or get stuck where you shouldn't.

Also, you want to check if you object isn't simetrical you can't end up with issues were when you turn your are suddenly in the wall that you need to account for.
 

Mikey3131

Member
you can run into issues like that just checking one point. you need to check the four corner and points in the middle until the gap is less than the tile size or your can end up with oddness where your pass through something you shouldn't or get stuck where you shouldn't.

Also, you want to check if you object isn't simetrical you can't end up with issues were when you turn your are suddenly in the wall that you need to account for.
That makes complete sense. My player object has an origin in the center, so we're passing center to the check, hence the problem. I'll do some poking around and see if I can get it working. Proper manners is to post the solution once I get it, right? For the next poor soul who runs into this?
 
Top