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

[GMS 2] Tilemap as Collision Maps - GMWolf

GMWolf

aka fel666
GM Version: GMS 2.0.1.33
Target Platform: ALL
Download: N/A
Links: Video Link


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:​
profile.jpgCheck out my Channel on Youtube for more tutorials! ​
 
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

aka fel666
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 ?
glad you liked it :)
You could do that. And it would be just as good. I just happened to organize it that way. No real difference.
 

spacerobot

Member
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?
 

GMWolf

aka fel666
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?
That is fairly strange. What are you sprite size origine settings? Is your tilemap offset by any amount?
 

spacerobot

Member
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.
 

GMWolf

aka fel666
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.
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?
 

spacerobot

Member
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;
      
        }
}
 
M

musicones

Guest
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
 

GMWolf

aka fel666
~~~~~~~~~
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.
 
M

musicones

Guest
I cannot see your screen cast. video is unavailable.
Aah, sorry for that... it's - unbelievable - my first youtube video upload. Changed visibility, i hope now others can see it...

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.
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;
 
N

n0k

Guest
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?
 

GMWolf

aka fel666
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?
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
 
T

tidlon

Guest
This is so much better than drawing objects to add collision :_P
 

flyinian

Member
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.
 
Top