RefresherTowel

GameMaker Tile Collisions

Sep 21st, 2022
196
1
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ********* Create ***************//
  2. bbox = new tile_bbox(mask_index); // Instance of the struct below
  3.  
  4. // ********* How to call it when moving (step event or something) *************** //
  5. bbox.move_collide(id, x, y, _vx, _vy);  // _vx and _vy are whatever your movement speeds are
  6.  
  7.  
  8. // ********* The struct ******************************//
  9. function tile_bbox(_mask) constructor
  10. {
  11.     /* Performs tile collision independent from object's bbox.
  12.      * Since we can use a separate mask here from the objects, that allows
  13.      * the object to use a different shaped mask for hit detection and not
  14.      * need a whole other "hurtbox" object.
  15.      *
  16.      * Plus this is actually faster and requires less round/floor/ceil nonsense
  17.      * to fix some internal junk.
  18.      *
  19.      * Note the "& 1" checks for odd numbered tiles as "solid", pretty usefull
  20.      * if you want waist high walls that cause movement collision but can be
  21.      * shot over with a gun or something.
  22.      */
  23.  
  24.     #macro TILE_SOLID 1
  25.     #macro TILE_ONE_WAY 2
  26.     #macro TILE_SIZE 16
  27.     #macro TILE_SIZE_M1 15
  28.    
  29.     #macro COLLIDE_VER_UP 1
  30.     #macro COLLIDE_VER_DOWN -1
  31.     #macro COLLIDE_VER_NONE 0
  32.     #macro COLLIDE_HOR_RIGHT 1
  33.     #macro COLLIDE_HOR_LEFT -1
  34.     #macro COLLIDE_HOR_NONE 0
  35.    
  36.     var _w = sprite_get_width(_mask),
  37.         _h = sprite_get_height(_mask),
  38.         _y_count = ceil(_h / TILE_SIZE),
  39.         _x_count = ceil(_w / TILE_SIZE);
  40.        
  41.     mask_sprite = _mask;
  42.    
  43.     cmap   = global.layer_collision;  
  44.     // or layer_tilemap_get_id(layer_get_id("collision_map"));
  45.     // Remember the id could change between rooms
  46.    
  47.     left   = -sprite_get_xoffset(_mask);
  48.     right  = _w - sprite_get_xoffset(_mask);
  49.     top    = -sprite_get_yoffset(_mask);
  50.     bottom = _h - sprite_get_yoffset(_mask);
  51.    
  52.     hor_count     = _y_count + 1;
  53.     hor_increment = (_h - 1) / _y_count;
  54.     ver_count     = _x_count + 1;
  55.     ver_increment = (_w - 1) / _x_count;
  56.    
  57.     on_horizontal = 0; // Useful for wall jumps
  58.     on_vertical = 0; // Can be used to set on_ground
  59.     on_one_way_platform = false;
  60.                
  61.     function move_collide(_this, _x, _y, _vx, _vy)
  62.     {
  63.         _x += _vx;
  64.         if (_vx > 0) _x = collide_right(_x, _y);
  65.         else if (_vx < 0) _x = collide_left(_x, _y);
  66.         else on_horizontal = COLLIDE_HOR_NONE;
  67.  
  68.         _y += _vy;
  69.         if (_vy > 0) _y = collide_bottom(_x, _y, _vy);
  70.         else if (_vy < 0) _y = collide_top(_x, _y);
  71.         else
  72.         {
  73.             on_vertical = COLLIDE_VER_NONE;
  74.             on_one_way_platform = false;
  75.         }
  76.        
  77.         _this.x = _x;
  78.         _this.y = _y;
  79.     }          
  80.                
  81.     function collide_right(_x, _y)
  82.     {
  83.         var _right = _x + right;
  84.         _y = round(_y + top);
  85.         for (var _i = 0; _i < hor_count; _i++)
  86.         {
  87.             if ((tilemap_get_at_pixel(cmap, _right, _y) & tile_index_mask) & 1)
  88.             {
  89.                 on_horizontal = COLLIDE_HOR_RIGHT;
  90.                 return (_right &~ TILE_SIZE_M1) - right;
  91.             }
  92.             _y += hor_increment;
  93.         }
  94.         on_horizontal = COLLIDE_HOR_NONE;
  95.         return _x;
  96.     }
  97.    
  98.     function collide_left(_x, _y)
  99.     {
  100.         var _left = _x + left;
  101.         _y = round(_y + top);
  102.         for (var _i = 0; _i < hor_count; _i++)
  103.         {
  104.             if ((tilemap_get_at_pixel(cmap, _left, _y) & tile_index_mask) & 1)
  105.             {
  106.                 on_horizontal = COLLIDE_HOR_LEFT;
  107.                 return (_left &~ TILE_SIZE_M1) + TILE_SIZE - left;
  108.             }
  109.             _y += hor_increment;
  110.         }
  111.         on_horizontal = COLLIDE_HOR_NONE;
  112.         return _x;
  113.     }
  114.    
  115.     function collide_top(_x, _y)
  116.     {
  117.         on_one_way_platform = false;
  118.         var _top = _y + top;
  119.         _x = round(_x + left);
  120.         for (var _i = 0; _i < ver_count; _i++)
  121.         {
  122.             if ((tilemap_get_at_pixel(cmap, _x, _top) & tile_index_mask) & 1)
  123.             {
  124.                 on_vertical = COLLIDE_VER_UP;
  125.                 return (_top &~ TILE_SIZE_M1) + TILE_SIZE - top;
  126.             }
  127.             _x += ver_increment;
  128.         }
  129.         on_vertical = COLLIDE_VER_NONE;
  130.         return _y;
  131.     }
  132.    
  133.     function collide_bottom(_x, _y, _vy)
  134.     {
  135.         // A bit different to account for one-way platforms
  136.        
  137.         var _bottom = _y + bottom,
  138.             _tile_top = _bottom &~ TILE_SIZE_M1,
  139.             _above_one_way = (_bottom - _vy) <= _tile_top;
  140.            
  141.         _x = round(_x + left);
  142.         for (var _i = 0; _i < ver_count; _i++)
  143.         {
  144.             var _tile_index = tilemap_get_at_pixel(cmap, _x, _bottom) & tile_index_mask,
  145.                 _on_one_way_platform = (_above_one_way && _tile_index == TILE_ONE_WAY);
  146.            
  147.             if (_tile_index & 1 || _on_one_way_platform)
  148.             {
  149.                 on_vertical = COLLIDE_VER_DOWN;
  150.                 on_one_way_platform = _on_one_way_platform;
  151.                 return _tile_top - bottom;
  152.             }
  153.             _x += ver_increment;
  154.         }
  155.         on_vertical = COLLIDE_VER_NONE;
  156.         return _y;
  157.     }
  158.    
  159.     function draw_mask(_x, _y)
  160.     {
  161.         draw_sprite(mask_sprite, 0, _x, _y);
  162.     }
  163.    
  164. }
Add Comment
Please, Sign In to add comment