# Tile collisions in step event vs script

R

#### Ralliare

##### Guest
I've read a few blog posts and watched a few different YouTubers go on about the benefits of using tile collisions in GM2. From having a play around with it it does seem like a great way to quickly draw collisions, especially on more complex leves. I don't think anyone like dumping loads of objects onto the old room editor.

There is one thing I have noticed when trying it out. The maths (and by extension everyone) says it only works with powers of 2. The only examples I can find at for 64x64 tile sets. So I thought I'd try out Heartbeasts implementation but go with 8x8 grid.

And then my headache started. I thought I must have coded something wrong as my player object sumk down and right one pixel. So I grabbed his project files, reworked the one code reference to tile sizes, updated the objects, sprites and tile sets to 8x8, and the same issue again. I tried the approach GMwolf used. And got the same issue.

I only understand the basic concept of the binary used, but from my understanding any power of 2 should work for tile size, and yet when I tried, 8, then 16 neither of these worked.

Anyone have any insight on this? I'd love to try this out in a game idea I've been tossing around that would require a large number of objects on screen so the performance boost would be useful.

tile_collide_at_points script
Code:
``````///@param tile_map_id
///@param point_arrays...
var tile_map_id = argument[0];

// Found variable
var found = false;

// for the point arrays
var vector2_x = 0;
var vector2_y = 1;

// Loop through the points and check for a tile
for (var i=1; i<argument_count; i++) {
var point = argument[i];
found = found || tilemap_get_at_pixel(tile_map_id, point[vector2_x], point[vector2_y]);
}

// return found
return found;``````
move_and_contact_tiles script called from player step event
Code:
``````///@param tile_map_id
///@param tile_size
///@param velocity_array
var tile_map_id = argument0;
var tile_size = argument1;
var velocity = argument2;

// For the velocity array
var vector2_x = 0;
var vector2_y = 1;

// Move horizontally
x += velocity[vector2_x];

// Right collisions
if velocity[vector2_x] > 0 {
var tile_right = tile_collide_at_points(tile_map_id, [bbox_right-1, bbox_top], [bbox_right-1, bbox_bottom-1]);
if tile_right {
x = bbox_right & ~(tile_size-1);
x -= bbox_right-x;
velocity[@ vector2_x] = 0;
}
} else {
var tile_left = tile_collide_at_points(tile_map_id, [bbox_left, bbox_top], [bbox_left, bbox_bottom-1]);
if tile_left {
x = bbox_left & ~(tile_size-1);
x += tile_size+x-bbox_left;
velocity[@ vector2_x] = 0;
}
}

// Move vertically
y += velocity[vector2_y];

// Vertical collisions
if velocity[vector2_y] > 0 {
var tile_bottom = tile_collide_at_points(tile_map_id, [bbox_left, bbox_bottom-1], [bbox_right-1, bbox_bottom-1]);
if tile_bottom {
y = bbox_bottom & ~(tile_size-1);
y -= bbox_bottom-y;
velocity[@ vector2_y] = 0;
}
} else {
var tile_top = tile_collide_at_points(tile_map_id, [bbox_left, bbox_top], [bbox_right-1, bbox_top]);
if tile_top {
y = bbox_top & ~(tile_size-1);
y += tile_size+y-bbox_top;
velocity[@ vector2_y] = 0;
}
}``````

#### Nocturne

##### Friendly Tyrant
Forum Staff
Moderator
Tile collisions will work at all sizes.... Use powers of 2 if you want to use bitshifting, but it's by no means a requirement...

R

#### Ralliare

##### Guest
Tile collisions will work at all sizes.... Use powers of 2 if you want to use bitshifting, but it's by no means a requirement...
I'd rather use bite shifting due to the performance benefits, and I'm fine with a grid being a power of 2, my issue is that the collisions are being seemingly calculated down and right by one for some unknown reason.

#### Jobo

##### Member
GMC Elder
I've not seen this myself... Can you isolate the issue in a small project that reproduces it and report a bug (and attach the project)?

#### rIKmAN

##### Member
@Ralliare
Was the GMWolf method the one used in his Youtube video on GMS2 Tilemap Collisions?

I followed that video through a while ago and it worked fine, then I then adjusted it to work with 32x32px tiles and that also worked fine.
IIRC I just changed / added a few numbers, but I'd have to go back and look at the code to tell you exactly what I changed as it was a while ago now.

Quickly looking at your code, you have a lot of "-1" dotted about your code, so I would assume one or more of these are incorrect and are causing your issue where things are 1px off.

R

#### Ralliare

##### Guest
That was the one I saw yes. the -1's come from Heartbeasts version.

I found a sample of code from Stefan Randa in which he does 16x16 collisions and it actually works for 8x8 but when testing why it worked I've come across some weirdness.

Here is the code for checking a upwards collision, C1 is top left, C2 is top right. both work perfectly fine and correctly return 1 when a collision occurs

Code:
``````    var c1 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_top) & tile_index_mask;
var c2 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_top) & tile_index_mask;
show_debug_message("------- C1 --------");
show_debug_message(tilemap);
show_debug_message(bbox_left);
show_debug_message(bbox_top);
show_debug_message(string(c1));
show_debug_message("------- C2 --------");
show_debug_message(tilemap);
show_debug_message(bbox_right);
show_debug_message(bbox_top);
show_debug_message(string(c2));

var tile_top = tile_collide_at_points(tilemap, [bbox_left, bbox_top], [bbox_right, bbox_top]);``````
So I then decided to modify Heartbeasts code to work with this method where I run the tilemap_get_at_pixel through the binary AND to see if this would make that code work universally, and discovered that something funky was going on.
Code:
``````///@param tile_map_id
///@param point_arrays...
var tile_map_id = argument[0];

// Found variable
var found = false;

// for the point arrays
var vector2_x = 0;
var vector2_y = 1;

// Loop through the points and check for a tile
for (var i=1; i<argument_count; i++) {
var point = argument[i];
show_debug_message("------- H" + string(i) + " --------");
var check = tilemap_get_at_pixel(tile_map_id, point[vector2_x], point[vector2_y]) & tile_index_mask;
show_debug_message(tile_map_id);
show_debug_message(point[vector2_x]);
show_debug_message(point[vector2_y]);
show_debug_message(string(check));

found = found || check;
}

// return found
return found;``````
And here is an example of a top right collision in my logs

------- C1 --------
1
52
48
524287
0
------- C2 --------
1
59
48
524287
1
------- H1 --------
1
52
48
524287
0
------- H2 --------
1
59
48
524287
0

All the numbers the same, the same function being called, but the result of C1 and C1 differ from the two results from the check function. I must be doing something wrong because from what I can see the data going into the 2 functions is identical but I'm getting 2 different results.

I've set-up a repo demonstrating the issue here bitbucket.org/codecomp/tile-collisions/overview on the weird-maths branch

Last edited by a moderator:

#### rIKmAN

##### Member
That was the one I saw yes. the -1's come from Heartbeasts version.
I think your issue is probably coming from mixing code from both tutorials, as I said I edited the GMWolf tutorial to work with 32px tiles without issue, and the fact you have all those -1's everywhere and your issue is related to things being 1px off is giving off red flags.

I'd say start fresh with just the original GMWolf code and go from there, it should work with any power of 2 tiles with the correct values adjusted.

If you are still struggling I can dig out the edited 32px code later tonight when I get home and show you the changes I made which might help you edit it again for 8px tiles. It was literally a few numbers though.

R

#### Ralliare

##### Guest
I think your issue is probably coming from mixing code from both tutorials, as I said I edited the GMWolf tutorial to work with 32px tiles without issue, and the fact you have all those -1's everywhere and your issue is related to things being 1px off is giving off red flags.
The only thing in the code I'm currently working on from Heartbeast is the function to check points, and that was only because I'm trying to make the code universal.

I just wrote a custom script and all it does is the following

my_custom_check fucntion
Code:
``````///@param tile_map_id
///@param point_1
///@param point_2

var tilemap = argument[0];
var point_1 = argument[1];
var point_2 = argument[2];

var check = tilemap_get_at_pixel(tilemap, point_1, point_2) & tile_index_mask;
return check;``````
Code:
``````var c1 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_top) & tile_index_mask; // Correct result
var wtf = my_custom_check(tilemap, bbox_left, bbox_top) // Always 0``````
I can;t work out why when called from a script these 2 give different results, I don;t want to have to rewrite the same logic repeatedly but can;t see why I'd need anything else when the numbers are all the same.

#### TheouAegis

##### Member
What if you just did

return tilemap_get_at_pixel(argument0, argument1, argument2) & tile_index_mask;

Or

return tilemap_get_at_pixel(argument[0], argument[1], argument[2]) & tile_index_mask;

In other words, skip the variable declarations and see if it work.s