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

Tile Pixel Collision System

C

ChaosX2

Guest
Hello,

I've been working on a tile collision system based on pixels and I would really appreciate any help in correcting my formula for the left, right, and bottom collisions (I have top working). Here's the other thread where I discovered the system and made an attempt if you need context for the problem.

The gist of it is that you create a surface to draw the tile sheet on and store it's data in a buffer, you then create a series of for loops to count the blank space (pixels) within the tiles and then store that count within a different buffer. It then calculates when a collision happens based on some comparisons. The for loop labeled "Top" works perfect but the other directions are off and I can't figure out why :/ I will be greatly indebted to anyone that can offer support to help figure out what's up.

TILE_SIZE is 64 and TILE_MAX is 1024. The tiles are on a 2048 x 2048 tile sheet.

Code:
//Draw Event

global.topHeightBuff = buffer_create(TILE_SIZE * TILE_MAX, buffer_fast, 1);
global.bottomHeightBuff = buffer_create(TILE_SIZE * TILE_MAX, buffer_fast, 1);
global.leftWidthBuff = buffer_create(TILE_SIZE * TILE_MAX, buffer_fast, 1);
global.rightWidthBuff = buffer_create(TILE_SIZE * TILE_MAX, buffer_fast, 1);

//Surface & buffer to store tiles
var surf = surface_create(2048, 2048);
var buff = buffer_create(TILE_SIZE * TILE_MAX * TILE_SIZE * 4, buffer_fixed, 1);

surface_set_target(surf);
draw_clear_alpha(0,0);

//Loop through tiles to draw
for (var i = 0; i < TILE_MAX; i++)
{
    var j = i mod 32;
    var k = i div 32;
    draw_tile(ts_EGM, i, 0, j * TILE_SIZE, k * TILE_SIZE);
}

surface_reset_target();
buffer_get_surface(buff, surf, 0, 0, 0);

//Nested loops to count the exact pixels of each tile
//Top
var t_y = 0;
for(var xx = 0; xx < (TILE_SIZE * TILE_MAX); xx++)
{
    var count = 0;
    if(xx > 0 && xx mod 2048 == 0)
    {
        //if(_y <= 1984)
        t_y +=(TILE_SIZE - 1); 
    }
  
    for(var yy = t_y; yy < (t_y + TILE_SIZE); yy++)
    {
        var pixel = buffer_peek(buff, (xx + (yy * TILE_SIZE * 32)) * 4, buffer_u32);
        if((pixel&0xff000000) != 0 || count == TILE_SIZE) break;
        count++;
    }
    buffer_poke(global.topHeightBuff, xx, buffer_u8, count);
}

//Down
var d_y = TILE_SIZE - 1;
//Nested loop to count the exact pixels of each tile
for(var xx = 0; xx < TILE_SIZE * TILE_MAX; xx++)
{
    var count = 0;
    if(xx > 0 && xx mod 2048 == 0)
    {
        //if(_y <= 1984)
        d_y += TILE_SIZE; 
    }
  
    for(var yy = d_y; yy >= (d_y - (TILE_SIZE - 1)); yy--)
    {
        var pixel = buffer_peek(buff, (xx + (yy * TILE_SIZE * 32)) * 4, buffer_u32);
        if((pixel&0xff000000) != 0 || count == TILE_SIZE) break;
        count++;
    }
    buffer_poke(global.bottomHeightBuff, xx, buffer_u8, count);
}

//Left
var l_x = 0;
for (var yy = 0; yy < TILE_SIZE * TILE_MAX; yy++)
{
   var count = 0;
   if(yy > 0 && yy mod 2048 == 0)
    l_x += (TILE_SIZE - 1);
 
   for (var xx = l_x; xx < (l_x + TILE_SIZE); xx++)
   {
      var pixel = buffer_peek(buff, (xx + (yy  * TILE_SIZE * 32)) * 4, buffer_u32);
      if ((pixel&0xff000000) != 0 || count == TILE_SIZE) break; 
      count++;
   }
      buffer_poke(global.leftWidthBuff, yy, buffer_u8, count);
}

//Right
var r_x = TILE_SIZE - 1;
for (var yy = 0; yy < TILE_SIZE * TILE_MAX; yy++)
{
   var count = 0;
   if(yy > 0 && yy mod 2048 == 0)
    r_x += TILE_SIZE;
 
   for (xx = r_x; xx >= (r_x - (TILE_SIZE - 1)); xx--)
   {
      var pixel = buffer_peek(buff, (xx + (yy  * TILE_SIZE * 32)) * 4, buffer_u32);
      if ((pixel&0xff000000) != 0 || count == TILE_SIZE) break; 
      count++;
   }
      buffer_poke(global.rightWidthBuff, yy, buffer_u8, count);
}

buffer_delete(buff);
surface_free(surf);

room_goto_next();
Below is the script where you would use the player's x, y, and direction as the arguments

Code:
var _x = argument0;  //x position
var _y = argument1; //y position
var dir = argument2; // direction player is facing

//Perform collision calculations
var t = tilemap_get_at_pixel(tile_id, _x, _y) & tile_index_mask;

var column = (_x&(TILE_SIZE - 1)) + (t * TILE_SIZE);
var row = (_y&(TILE_SIZE - 1)) - (t * TILE_SIZE);

var h_top = buffer_peek(global.topHeightBuff, column, buffer_u8);
var h_bottom = buffer_peek(global.bottomHeightBuff, column, buffer_u8);

var w_left = buffer_peek(global.leftWidthBuff, row, buffer_u8);
var w_right = buffer_peek(global.rightWidthBuff, row, buffer_u8);

var xx = _x&(TILE_SIZE - 1);
var yy = _y&(TILE_SIZE - 1);

//Left collisions
if(dir == 0)
{
   if(w_left == 0) return true;
   if(w_left == TILE_SIZE) return false;
   if(xx <= w_left) return true;
   return false;
   buffer_delete(global.leftWidthBuff);
}

//Bottom collisions
if(dir == 90)
{
   if(h_bottom == 0) return true;
   if(h_bottom == TILE_SIZE) return false;
   if(yy <= h_bottom) return true;
   return false;
   buffer_delete(global.bottomHeightBuff);
}

//Right collisions
if(dir == 180)
{
   if(w_right == 0) return true;
   if(w_right == TILE_SIZE) return false;
   if(xx >= w_right) return true;
   return false;
   buffer_delete(global.rightWidthBuff);
}

//Top collisions
if(dir == 270)
{
   if (h_top == 0) return true;
   if(h_top == TILE_SIZE) return false;
   if(yy >= h_top) return true;
   return false;
   buffer_delete(global.topHeightBuff);
}
 
C

ChaosX2

Guest
bump
I made adjustments for 3 out of the 4 loops. Collision from below a tile (walking up) works now. But I still can't get left and right to work.

Code:
//Down
var d_y = TILE_SIZE - 1;
for(var xx = 0; xx < (TILE_SIZE * TILE_MAX); xx++)
{
    var count = 64;
    if(xx > 0 && xx mod 2048 == 0) d_y += TILE_SIZE - 1; 
      
    for(var yy = d_y; yy >= (d_y - (TILE_SIZE - 1)); yy--)
    {
        var pixel = buffer_peek(buff, (xx + (yy * TILE_SIZE * 32)) * 4, buffer_u32);
        if((pixel&0xff000000) != 0 || count == 0) break;
        count--;
    }
    buffer_poke(global.bottomHeightBuff, xx, buffer_u8, count);
}


//Left
var l_x = 0;
for (var yy = 0; yy < TILE_SIZE * TILE_MAX; yy++)
{
   var count = 0;
   if(yy > 0 && yy mod 2048 == 0) l_x += (TILE_SIZE - 1);
 
   for(var xx = l_x; xx < (l_x + TILE_SIZE); xx++)
   {
      var pixel = buffer_peek(buff, (xx + (yy  * TILE_SIZE * 32)) * 4, buffer_u32);
      if ((pixel&0xff000000) != 0 || count == TILE_SIZE) break; 
      count++;
   }
      buffer_poke(global.leftWidthBuff, yy, buffer_u8, count);
}

//Right
var r_x = TILE_SIZE - 1;
for (var yy = 0; yy < TILE_SIZE * TILE_MAX; yy++)
{
   var count = 64;
   if(yy > 0 && yy mod 2048 == 0) r_x += TILE_SIZE - 1;
 
   for(xx = r_x; xx >= r_x - (TILE_SIZE - 1); xx--)
   {
      var pixel = buffer_peek(buff, (xx + (yy  * TILE_SIZE * 32)) * 4, buffer_u32);
      if ((pixel&0xff000000) != 0 || count == 0) break; 
      count--;
   }
      buffer_poke(global.rightWidthBuff, yy, buffer_u8, count);
}

I suspect that left and right collision isn't working because t is calculating the index in the tilemap from left to right then goes down a row and counts left to right again. This matches how the top and down for loop counts the tilemap, but the right and left for loops counts the map from top to bottom, moves over a column and counts again. If this is the case, I need a way to properly calculate the variable row and I'm uncertain of how to do it, or if I'm even on the right track.

Ex: 2048 x 2048 tile map. 32 tiles across in height and width. From left to right is 0, 1, 2, all the way to 63. Tile 64 starts with the tile just below the first tile. I feel I need a way to make this index tile 1 instead of 64 and count downwards to 63 and then move to the top tile in the second column as tile number 64.

Any help would be much appreciated.


Code:
var _x = argument0;
var _y = argument1;
var dir = argument2;

//Perform collision calculations
var t = tilemap_get_at_pixel(tile_id, _x, _y) & tile_index_mask;

var column = (_x&(TILE_SIZE - 1)) + (t * TILE_SIZE);
var row = (_y&(TILE_SIZE - 1)) - (t * TILE_SIZE);

var h_top = buffer_peek(global.topHeightBuff, column, buffer_u8);
var h_bottom = buffer_peek(global.bottomHeightBuff, column, buffer_u8);
var w_left = buffer_peek(global.leftWidthBuff, row, buffer_u8);
var w_right = buffer_peek(global.rightWidthBuff, row, buffer_u8);

var xx = _x&(TILE_SIZE - 1);
var yy = _y&(TILE_SIZE - 1);

//Left collisions
if(dir == 0)
{
   if(w_left == 0) return true;
   if(w_left == TILE_SIZE) return false;
   if(xx >= w_left) return true;
   return false;
   buffer_delete(global.leftWidthBuff);
}

//Bottom collisions
if(dir == 90)
{
   if(h_bottom == 0) return false;
   if(h_bottom == TILE_SIZE) return true;
   if(yy <= h_bottom) return true;
   return false;
   buffer_delete(global.bottomHeightBuff);
}

//Right collisions
if(dir == 180)
{
   if(w_right == 0) return false;
   if(w_right == TILE_SIZE) return true;
   if(xx <= w_right) return true;
   return false;
   buffer_delete(global.rightWidthBuff);
}

//Top collisions
if(dir == 270)
{
   if (h_top == 0) return true;
   if(h_top == TILE_SIZE - 1) return false;
   if(yy >= h_top) return true;
   return false;
   buffer_delete(global.topHeightBuff);
}
 
C

ChaosX2

Guest
bump

I believe the variable row needs to be calculated differently if I'm not mistaken and I'm unsure how...
 
Top