GML Tile Collision Problems

NeoShade

Member
Hi All,

Playing around with a zelda-like game while following Shaun Spalding's ARPG tutorial series. I'm trying to implement tile-based collisions (which is covered in the 3rd episode released to Patrons on friday) but using a bounding box insted of a single pixel as Shaun did. To accomplish this, I've built in the code from his older Tile-Based collisions video (
). It's working mostly, but I've encountered a strange bug:

The bug can be reproduced by placing a row of collision tiles horizontally in the room, and approaching them diagonally from the top left or top right. Occasionally, upon colliding with the tiles, the player object will jump left or right a few pixels.

Step event and scripts for the player object are listed below. All other code is irrelevant. My player's sprite is 16x24, has an origin of [8,23], and has a rectangular bounding box defined by the points [0,14] and [15,23].

If anybody has some insight into what's going on, I'd be very grateful.

Code:
///STEP EVENT

// Get player input
key_up = keyboard_check(vk_up) || keyboard_check(ord("W"));
key_dn = keyboard_check(vk_down) || keyboard_check(ord("S"));
key_lf = keyboard_check(vk_left) || keyboard_check(ord("A"));
key_rt = keyboard_check(vk_right) || keyboard_check(ord("D"));

// Get input vector
input_dir = point_direction(0, 0, (key_rt - key_lf), (key_dn - key_up));
input_mag = (key_rt - key_lf != 0) || (key_dn - key_up != 0);

// Calculate movement vector
x_speed = lengthdir_x((input_mag * walk_speed), input_dir);
y_speed = lengthdir_y((input_mag * walk_speed), input_dir);

//
//if (input_mag == 0)
//    { x = round(x); y = round(y); }

// Comit movement
player_collision();

// Save previous sprite to compare later
var _oldsprite = sprite_index;

// Update sprite index
if (input_mag != 0)
    {
    direction = input_dir;
    sprite_index = sprite_walk;
    }
else
    {
    sprite_index = sprite_idle;
    }

// Reset local frame whenever sprite index changes
if (_oldsprite != sprite_index)
    { local_frame = 0; }

// Update image index
player_animate_sprite();
Code:
/// PLAYER_COLLISION SCRIPT

var _collision = false;
var _bbox_x_side;
var _bbox_y_side;

if (x_speed > 0) { _bbox_x_side = bbox_right; } else { _bbox_x_side = bbox_left; }
if (y_speed > 0) { _bbox_y_side = bbox_bottom; } else { _bbox_y_side = bbox_top; }

if (tilemap_get_at_pixel(collision_map, _bbox_x_side + x_speed, bbox_top) != 0)
or (tilemap_get_at_pixel(collision_map, _bbox_x_side + x_speed, bbox_bottom) != 0)
    {
    if (x_speed > 0) { x = x - (x mod tile_size) + (tile_size - 1) - (bbox_right - x); }
    else { x = x - (x mod tile_size) - (bbox_left - x); }
    x_speed = 0;
    _collision = true;
    }

if (tilemap_get_at_pixel(collision_map, bbox_left, _bbox_y_side + y_speed) != 0)
or (tilemap_get_at_pixel(collision_map, bbox_right, _bbox_y_side + y_speed) != 0)
    {
    if (y_speed > 0) { y = y - (y mod tile_size) + (tile_size - 1) - (bbox_bottom - y); }
    else { y = y - (y mod tile_size) - (bbox_top - y); }
    y_speed = 0;
    _collision = true;
    }


// Commit movements
x += x_speed;
y += y_speed;

return _collision;
 
Top