[GMS 2] Tilemap as Collision Maps - GMWolf

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

  1. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,160
    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.jpg Check out my Channel on Youtube for more tutorials! ​
     
    hippyman, MadZenno, ChaosX2 and 4 others like this.
  2. Daniel Jackson

    Daniel Jackson Member

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

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,160
    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.
     
    Lonewolff and Daniel Jackson like this.
  4. Daniel Jackson

    Daniel Jackson Member

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

    spacerobot Member

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

    GMWolf aka fel666

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

    spacerobot Member

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

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,160
    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. spacerobot

    spacerobot Member

    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;
          
            }
    }
    
     
  10. Galladhan

    Galladhan Member

    Joined:
    Jul 1, 2016
    Posts:
    119
    Great tutorial! Works like a charm. Thank you for sharing it, mate :)
     
    GMWolf likes this.
  11. musicones

    musicones Member

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

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,160
    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. musicones

    musicones Member

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

    n0k Member

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

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,160
    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. tidlon

    tidlon Member

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

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