# [GMS 2] Tilemap as Collision Maps - GMWolf

Discussion in 'Tutorials' started by GMWolf, Nov 20, 2016.

Tags:
1. ### GMWolfaka fel666

Joined:
Jun 21, 2016
Posts:
3,241
GM Version: GMS 2.0.1.33
Target Platform: ALL

Summary:
Tile maps in GMS 2 allow you to quickly and easily build up the graphics for your level. However, They are just as powerfull when designing the layout and handling collisions in your games.
In this video tutorial, i will show yout how to add a tile map to your room and use it as a collision map for your player.
We will be building a simple platformer engine using a single player objects, and a simple tilemap.
Tutorial:​

Check out my Channel on Youtube for more tutorials! ​

hippyman, MadZenno, ChaosX2 and 4 others like this.
2. ### Daniel JacksonMember

Joined:
Jun 21, 2016
Posts:
109
Interesting tutorial. Looks like a very solid system!
One thing I'm curious about. Why is the vertical speed handled by the two different variables dy and v_speed ?
Why can't you just do dy += grav, and when there is a collision set dy=0 ?

GMWolf likes this.
3. ### GMWolfaka fel666

Joined:
Jun 21, 2016
Posts:
3,241
You could do that. And it would be just as good. I just happened to organize it that way. No real difference.

Lonewolff and Daniel Jackson like this.
4. ### Daniel JacksonMember

Joined:
Jun 21, 2016
Posts:
109
Ah, I thought I was missing some kind of trick or optimization. Thanks for clarifying!

5. ### spacerobotMember

Joined:
Jun 20, 2016
Posts:
80
Awesome tutorial. I am using 16 x 16 tiles. Everything seems to be working except for one thing. I am always a full tile above the floor when I drop. I am never against the floor itself. Here is my downwards fall y setting:
Code:
```y = ((bbox_bottom & ~15) - 1) - sprite_bbox_bottom;
```
Did I set that wrong or should that work?

6. ### GMWolfaka fel666

Joined:
Jun 21, 2016
Posts:
3,241
That is fairly strange. What are you sprite size origine settings? Is your tilemap offset by any amount?

Lonewolff likes this.
7. ### spacerobotMember

Joined:
Jun 20, 2016
Posts:
80
My tilemap offset x and y are 0. Player sprite is 16 x 16 square with a rectangle collision on the whole sprite, origin is middle center.

8. ### GMWolfaka fel666

Joined:
Jun 21, 2016
Posts:
3,241
Very strange. I will look into it. Does the problem persist with a 14x14 player?
Are you sure you are using the same/ equivalent code?

Lonewolff likes this.
9. ### spacerobotMember

Joined:
Jun 20, 2016
Posts:
80
EDIT: Yes it also does it with 14 x 14

Here is the step event:

Code:
```var t1 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_bottom + 1) & tile_index_mask;
var t2 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_bottom + 1) & tile_index_mask;
if (t1 != 0 || t2 != 0) {
if (keyboard_check(vk_space)) {
v_speed = -jumpHeight;
}
}

var dx = moveSpeed * (keyboard_check(vk_right) - keyboard_check(vk_left));
var dy = v_speed;
v_speed += grav;

// Do vertical Move

y += dy;
if ( dy > 0) { //downwards
var t1 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_bottom) & tile_index_mask;
var t2 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_bottom) & tile_index_mask;

if (t1 != 0 || t2 != 0) {
y = ((bbox_bottom & ~15) - 1) - sprite_bbox_bottom;
v_speed = 0;
}

} else { //upwards
var t1 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_top) & tile_index_mask;
var t2 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_top) & tile_index_mask;

if (t1 != 0 || t2 != 0) {
y = ((bbox_top + 16) & ~15) - sprite_bbox_top;
v_speed = 0;
}
}

//Horizontal Movement

x += dx;
if ( dx > 0) { //right
var t1 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_top) & tile_index_mask;
var t2 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_bottom) & tile_index_mask;

if (t1 != 0 || t2 != 0) {
x = ((bbox_right & ~15) - 1) - sprite_bbox_right;

}

} else { //left
var t1 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_top) & tile_index_mask;
var t2 =  tilemap_get_at_pixel(tilemap, bbox_left, bbox_bottom) & tile_index_mask;

if (t1 != 0 || t2 != 0) {
x = ((bbox_left + 16) & ~15) - sprite_bbox_left;

}
}
```

Joined:
Jul 1, 2016
Posts:
119
Great tutorial! Works like a charm. Thank you for sharing it, mate

GMWolf likes this.
11. ### musiconesMember

Joined:
Nov 26, 2016
Posts:
8
Hi there,

thanks for the tutorial. I have two issues with the collision.
I show it up in this screencast:

Some infos:
• I use 64x64 tiles as in tutorial, sprite is 128x64.
• The room is 1920x1080, so the tiles do not fit exactly on the bottom they begin a bit outside of the room
• Player dimensions: 75 x 94 for all sprites (idle, move, attack)
• Player origin: Middle Centre
Some code:

player - create:

Code:
```// basic player vars
move_speed = 8;
jump_impulse = 16;
grav = 0.75;
v_speed = 0;
dx = 0;
dy = 0;
t1 = 0;
t2 = 0;

// Tile map info
var l_id = layer_get_id("collision_map");
tilemap = layer_tilemap_get_id(l_id);

// sprite info
sprite_bbox_left = sprite_get_bbox_left(sprite_index) - sprite_get_xoffset(sprite_index);
sprite_bbox_right = sprite_get_bbox_right(sprite_index) - sprite_get_xoffset(sprite_index);
sprite_bbox_bottom = sprite_get_bbox_bottom(sprite_index) - sprite_get_yoffset(sprite_index);
sprite_bbox_top = sprite_get_bbox_top(sprite_index) - sprite_get_yoffset(sprite_index);

```
player - step:
Code:
```/// @description Insert description here

// do jump
t1 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_bottom + 1) & tile_index_mask;
t2 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_bottom + 1) & tile_index_mask;

if (t1 != 0 || t2 != 0) && (keyboard_check(vk_up)) v_speed = -jump_impulse;

dx = move_speed * (keyboard_check(vk_right) - (keyboard_check(vk_left)));
dy = v_speed;
v_speed += grav;

// do vertical move

y += dy;

if (dy > 0) { // downwards
t1 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_bottom) & tile_index_mask;
t2 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_bottom) & tile_index_mask;

if (t1 != 0 || t2 != 0) {
y = ((bbox_bottom & ~ 63) - 1) - sprite_bbox_bottom;
v_speed = 0;
}
} else { // upwards
t1 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_top) & tile_index_mask;
t2 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_top) & tile_index_mask;

if (t1 != 0 || t2 != 0) {
y = ((bbox_top + 64) & ~ 63) - sprite_bbox_top;
v_speed = 0;
}
}

if (dx == 0) sprite_index = knight_1_idle
else sprite_index = knight_1_move;

if (dx < 0) image_xscale = 1 else
if (dx > 0) image_xscale = -1;

if (keyboard_check(vk_space)) sprite_index = knight_1_atk;
if (keyboard_check(vk_rcontrol)) sprite_index = knight_1_magic;

// do horizontal move
x += dx;

if (dx > 0) { // right

var t1 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_top) & tile_index_mask;
var t2 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_bottom) & tile_index_mask;

if (t1 != 0 || t2 != 0) {
x = ((bbox_right & ~ 63) - 1) - sprite_bbox_right;
}
} else

if (dx < 0) { // left

var t1 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_top) & tile_index_mask;
var t2 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_bottom) & tile_index_mask;

if (t1 != 0 || t2 != 0) {
x = ((bbox_left + 64) & ~ 63) - sprite_bbox_left;
}
}
```
The code should be 99% of what you have shown...so what makes my player falling into infinity...

Thanks and regards
Antonio

12. ### GMWolfaka fel666

Joined:
Jun 21, 2016
Posts:
3,241
I cannot see your screen cast. video is unavailable.

However I believe I know what the issue is. Your player is wider than the tiles.

As explained at the beginning of the video, you have to check more points if your object is wider. In your case, a third point in the middle of the other two should be enough.
Modifying the example to check for a third point should be relatively straight forward.

13. ### musiconesMember

Joined:
Nov 26, 2016
Posts:
8
Aah, sorry for that... it's - unbelievable - my first youtube video upload. Changed visibility, i hope now others can see it...

Hm...missed that, need to see the video again.. anyway, i tried to do that now, but that doesn't work either, maybe my calculations are wrong.
Here is what if have done:
Code:
```// calc a third centered point
YCenter = bbox_top  + ((bbox_bottom - bbox_top) / 2);  // between top and bottom
XCenter = bbox_left + ((bbox_right - bbox_left) / 2);  // between left and right

// in jump part:
t3 = tilemap_get_at_pixel(tilemap, XCenter, bbox_bottom + 1) & tile_index_mask;
if (t1 != 0 || t2 != 0 || t3 != 0) && (keyboard_check(vk_up)) v_speed = -jump_impulse;
...
// downwards
t3 = tilemap_get_at_pixel(tilemap, XCenter, bbox_bottom) & tile_index_mask;
...
// upwards
t3 = tilemap_get_at_pixel(tilemap, XCenter, bbox_top) & tile_index_mask;
...
// right
t3 = tilemap_get_at_pixel(tilemap, bbox_right, YCenter) & tile_index_mask;
...
// left
t3 = tilemap_get_at_pixel(tilemap, bbox_left, YCenter) & tile_index_mask;

```

14. ### n0kMember

Joined:
Sep 25, 2018
Posts:
1
This is interesting, but is this easiest than place_metting to do the jumps, slopes, and gravity? and What about the enemies moves? mh... what is better?

15. ### GMWolfaka fel666

Joined:
Jun 21, 2016
Posts:
3,241
this is to collide with tiles. place meeting doesnt work with tiles.

the same principle can be applied to any object, not just the player object

16. ### tidlonMember

Joined:
Nov 10, 2018
Posts:
9
This is so much better than drawing objects to add collision :_P

17. ### flyinianMember

Joined:
Feb 5, 2018
Posts:
60
Hey all. I am currently attempting to get this tile collision to work but, haven't yet. However, i believe I managed to narrow what might be breaking the code for me. When I disable the "else" statements within the "if" statements the player collides with the tile and i am able to move left and right. However, when i enable the "else" statements, the player instantly goes down vertically and off to the right...I also go vertically down and off to the right when the entire code is active. I have stuck many hours into attempting to get this code to work and I decided to try my hand here.

My player is 32 x 32 and the tiles are 64 x 64. So it can't be the player size being to big and bypassing the collision checking.

Here is the collision code:

Code:
```var dx = move_speed * (keyboard_check(vk_right) - (keyboard_check(vk_left)));
var dy = v_speed;
v_speed += grav;

//vertical

y += dy;
if ( dy > 0)
{
//down
var t1 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_bottom) & tile_index_mask;
var t2 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_bottom) & tile_index_mask;

if (t1 != 0 || t2 != 0)

{
y = ((bbox_bottom & ~ 63) -1) - sprite_bbox_bottom;
v_speed = 0;
}
}

else

{
///up
var t1 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_top) & tile_index_mask;
var t2 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_top) & tile_index_mask;

if(t1 != 0 || t2 = 0)
{
y = ((bbox_top + 64) & ~63) - sprite_bbox_top;
v_speed = 0;

}

}

///___________________
x += dx;

///right
if ( dx > 0)
{

var t1 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_top) & tile_index_mask;
var t2 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_bottom) & tile_index_mask;

if (t1 != 0 || t2 != 0)

{
x = ((bbox_right & ~ 63) -1) - sprite_bbox_right;

}

}

else
//left
{
var t1 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_top) & tile_index_mask;
var t2 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_bottom) & tile_index_mask;

if(t1 != 0 || t2 = 0)
{
x = ((bbox_left + 64) & ~63) - sprite_bbox_left;

}

}
```

Here is the variable code for the player:
Code:
```move_speed = 8;
jump_impulse = 21;
grav = 0.75;
v_speed = 0;

//tilemap information
var l = layer_get_id("collision_map");
tilemap = layer_tilemap_get_id(l);

//sprite info
sprite_bbox_left = sprite_get_bbox_left(sprite_index) - sprite_get_xoffset(sprite_index);
sprite_bbox_right = sprite_get_bbox_right(sprite_index) - sprite_get_xoffset(sprite_index);
sprite_bbox_bottom = sprite_get_bbox_bottom(sprite_index) - sprite_get_yoffset(sprite_index);
sprite_bbox_top = sprite_get_bbox_top(sprite_index) - sprite_get_yoffset(sprite_index);```

Thank you.