Tile Collision Problem

T

Toxicosis

Guest
Greetings.

I implemented a tile collision system in a new project- I needed lots more obstacles, thousands of them, multiple sizes, and not necessarily on a grid, with a fixed size. Instances wouldn't cut it. Even if they merged with each other it still wouldn't be enough, I can't have 65k instances in the room. It was no use.

So I made something else. I'm using a tile collider, which checks the player against the tiles in the room. They're fully graphic resources with about a third of the overhead, running nothing while outside the screen, it seemed like a good answer.

There's just a problem with them- they are somehow misaligned, despite being placed right up to the 32x32 grid! Even with all the tiles being exactly the same, I can cling close to a row or column of tiles, and moving left or right, suddenly find myself hitting something that's clearly aligned with the surface.

Here's the code. Bit messy, though.

Code:
//This will create an array, then transfer all the values to a ds_grid.
draw = true;

//Start by creating a tiles list to get all the tiles in the room.
var tiles = tile_get_ids();

//The accomodate variable holds the number of tiles.
//tilelength holds the number of tiles in the grid that will be created.
var tilelength = 1;
var accomodate = array_length_1d(tiles);

//Adapt tilelength until we can hold accomodate tiles in it.
//Should be a power of 2!
while tilelength < accomodate
{
tilelength = tilelength*2;
}

//Then create a ds_grid, ds_walls, with an x, y, and number.
ds_walls = ds_grid_create(3,tilelength);
ds_walls_128 = ds_grid_create(3,tilelength);

//Each of the entries in the ds_grid must be filled with the x, y, and number.
for (var i = 0; i < accomodate; i++;)
    {
    if tile_get_height(tiles[i]) == 32
        {
        ds_grid_set(ds_walls,0,i,i);
        ds_grid_set(ds_walls,1,i,tile_get_x(tiles[i]));
        ds_grid_set(ds_walls,2,i,tile_get_y(tiles[i]));
        }
    if tile_exists(tiles[i])
    if tile_get_height(tiles[i]) == 128
        {
        ds_grid_set(ds_walls_128,0,i,i);
        ds_grid_set(ds_walls_128,1,i,tile_get_x(tiles[i]));
        ds_grid_set(ds_walls_128,2,i,tile_get_y(tiles[i]));
        }
    }
//Sort the grid for swift elimination.
ds_grid_sort(ds_walls,1,true);
ds_grid_sort(ds_walls_128,1,true);

//Tell the colliders what grid they need.
global.ds_walls = ds_walls;
global.ds_walls_128 = ds_walls_128;


Code:
/*Check a ds_grid with a brick size;
x=arg0;
y=arg1;
arg2: ds_grid in question.
arg3: block_size*/

ds_target = argument2;
collision_size = argument3;

var x_left = argument0+bbox_left-x;
var x_right = argument0+bbox_right-x;
var y_top = argument1+bbox_top-y;
var y_bottom = argument1+bbox_bottom-y;

var i = ds_grid_height(ds_target)/2;
var j = i/2;
var left_wrap;
var right_wrap;

//Iterate i until we have the first one to hit the right edge.
while (j >= 1)
{
if ds_grid_get(ds_target,1,i) < x_right i+=j;
else i-=j;
j=j/2;
}
right_wrap = i;

if i != 1
{
//Iterate i until we have the first one to hit the left edge.
i = ds_grid_height(ds_target)/2;
j = i/2;
while (j >= 1)
{
if ds_grid_get(ds_target,1,i)+collision_size > x_left i-=j;
else i+=j;
j=j/2;
}
left_wrap = i;
}
else
left_wrap = 1;

//---------------------------------------------
//now...

var left_edge;
var top_edge;

for (i = left_wrap; i <= right_wrap; i++)
{
left_edge = ds_grid_get(ds_target,1,i);
if (left_edge <= x_right)
if (left_edge+collision_size >= x_left)
    {
    top_edge = ds_grid_get(ds_target,2,i);
    if (top_edge+collision_size >= y_top)
    if (top_edge <= y_bottom)
        {
        return i;
        }
    }
}
return false;


Code:
/*
OK, here's the deal...
argument0 = x;
argument1 = y;
argument2 = root for arguments 2 and 3 to use on the collisions.

Argument2 should be checked against a list.
Then specific ds_grids will be checked.
We can do with passing a size argument, too.
Make the collider generic, accepting any ds_grid,
and any size for the squares.

argument0 = x;
argument1 = y;
argument2 = List to check.
argument3 = Size of block.
*/

//0 just parses the default.
if argument2 == 0
{
return scr_collide_generic(argument0,argument1,ds_walls,32);
}

//1 will parse the default and then the 128-sized block.
if argument2 == 1
{
var collided = scr_collide_generic(argument0,argument1,global.ds_walls,32);
if collided != false return collided;
collided = scr_collide_generic(argument0,argument1,global.ds_walls_128,128);
return collided;
}
 
Top