JealousCrow
Member
Hi all,
Context:
Getting back into a game maker project after over a year and was playing around with some code and functionality I have posted below (not sure what happened to my old forum account but had to register again even though I have on here for at least 5 years now?). The code seemingly works fine when the sprite size is even numbered (i.e., 30x30 etc.) and smaller than the tile size and if I need to go bigger I can add more vertices to check. The game is top down and the walls I am colliding with are randomly generated tiles. The issues only seems to happen when going left AND when sprite size is odd. I am using the automatic ellipse collision mask. The size of the sprite in the gif example is 29x29 and the tile size references in the code as CELL_HEIGHT and CELL_WIDTH are both 32. I have added code that allows the player character to slide around corner walls, but when fully commenting that code out the issue is still present. You will notice I have a combination of tile and object based collisions, this is on purpose as I am combining the buttery smooth movement code for awkwardly shaped objects and a tile collision system for proc generated levels.
Issue:
When moving left AND colliding with a wall of tiles where no opening exists on the bottom or top left corners, the player shoots down and snaps to lower sections of the grid. This will force the player through any tiles if there are any below it and pop out on the other side. If an opening exists on the top or bottom the code to slide slowly up or down around the corner executes as intended.
Is this an issue with the bit-wise operators being used in the tile collision and can I resolve this? Is this a limitation of calculating tile collisions using this method and should I just ensure all my mask indices are even numbered? If you need any other context please let me know and I can update the post.
I appreciate any and all information shared!
Example gif of the problem.
Code:
Context:
Getting back into a game maker project after over a year and was playing around with some code and functionality I have posted below (not sure what happened to my old forum account but had to register again even though I have on here for at least 5 years now?). The code seemingly works fine when the sprite size is even numbered (i.e., 30x30 etc.) and smaller than the tile size and if I need to go bigger I can add more vertices to check. The game is top down and the walls I am colliding with are randomly generated tiles. The issues only seems to happen when going left AND when sprite size is odd. I am using the automatic ellipse collision mask. The size of the sprite in the gif example is 29x29 and the tile size references in the code as CELL_HEIGHT and CELL_WIDTH are both 32. I have added code that allows the player character to slide around corner walls, but when fully commenting that code out the issue is still present. You will notice I have a combination of tile and object based collisions, this is on purpose as I am combining the buttery smooth movement code for awkwardly shaped objects and a tile collision system for proc generated levels.
Issue:
When moving left AND colliding with a wall of tiles where no opening exists on the bottom or top left corners, the player shoots down and snaps to lower sections of the grid. This will force the player through any tiles if there are any below it and pop out on the other side. If an opening exists on the top or bottom the code to slide slowly up or down around the corner executes as intended.
Is this an issue with the bit-wise operators being used in the tile collision and can I resolve this? Is this a limitation of calculating tile collisions using this method and should I just ensure all my mask indices are even numbered? If you need any other context please let me know and I can update the post.
I appreciate any and all information shared!
Example gif of the problem.
Code:
GML:
/// @description Tile Collisions
//@WARNING these collisions apparently do not work for sprite sizes that are in odd numbers?
//If the collider is larger than the tile size then you need to check more points than just the corners.
//////////////////////////////////////////////////////////////////////////////
//////////////TILE COLLISIONS////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
var width_slide_distance = bbox_right - bbox_left ; //pixels to check for colliding with corners to slide around them
var height_slide_distance = bbox_bottom - bbox_top;
y += ySpeed;
//Moving Up or Down
#region Tile Collisions on the Y-Axis
//Moving Down
if (ySpeed > 0) {
//get tile map info
var bot_left = tilemap_get_at_pixel(tilemap, bbox_left, bbox_bottom) & tile_index_mask;
var bot_right = tilemap_get_at_pixel(tilemap, bbox_right, bbox_bottom) & tile_index_mask;
//Get info for sliding when moving down
var bot_right_slide_left = tilemap_get_at_pixel(tilemap, bbox_right - height_slide_distance, bbox_bottom) & tile_index_mask;
var bot_left_slide_right = tilemap_get_at_pixel(tilemap, bbox_left + height_slide_distance, bbox_bottom) & tile_index_mask;
//if both bottom left and right corners are in contact with tiles, stop
if (bot_left != 0 and bot_right != 0) {
y = ((bbox_bottom & ~(CELL_HEIGHT-1)) - 1) - spriteBBBottom;
ySpeed = 0;
}
else {
//tile on bottom left, but not right so try to slide right
if (bot_left != 0 and bot_right == 0) {
//check if there is a tile to the right of the bottom left corner
if (bot_left_slide_right == 0) {
if (!input_left) && (!place_meeting(x+2, y, oParWall)) {
x += 2;
}
y = ((bbox_bottom & ~(CELL_HEIGHT-1)) - 1) - spriteBBBottom;
ySpeed = 0;
}
else {
y = ((bbox_bottom & ~(CELL_HEIGHT-1)) - 1) - spriteBBBottom;
ySpeed = 0;
}
}
if (bot_left == 0 and bot_right != 0){
if (bot_right_slide_left == 0) {
if (!input_right) && (!place_meeting(x-2, y, oParWall)){
x -= 2;
}
y = ((bbox_bottom & ~(CELL_HEIGHT-1)) - 1) - spriteBBBottom;
ySpeed = 0;
}
else {
y = ((bbox_bottom & ~(CELL_HEIGHT-1)) - 1) - spriteBBBottom;
ySpeed = 0;
}
}
}
}
//Moving Up
else {
var top_left = tilemap_get_at_pixel(tilemap, bbox_left, bbox_top) & tile_index_mask;
var top_right = tilemap_get_at_pixel(tilemap, bbox_right, bbox_top) & tile_index_mask;
//Get info for sliding up
var top_right_slide_left = tilemap_get_at_pixel(tilemap, bbox_right - height_slide_distance, bbox_top) & tile_index_mask;
var top_left_slide_right = tilemap_get_at_pixel(tilemap, bbox_left + height_slide_distance, bbox_top) & tile_index_mask;
if (top_left != 0 and top_right != 0) {
y = ((bbox_top + CELL_HEIGHT) & ~(CELL_HEIGHT-1)) - spriteBBTop;
ySpeed = 0;
}
else {
if (top_left != 0 and top_right == 0) { //tile on bottom left, try to slide right
if (top_left_slide_right == 0) { // if there is no tile a slide distance away to the right
if (!input_left) && (!place_meeting(x+2, y, oParWall)) {
x += 2;
}
y = ((bbox_top + CELL_HEIGHT) & ~(CELL_HEIGHT-1)) - spriteBBTop;
ySpeed = 0;
}
else {
y = ((bbox_top + CELL_HEIGHT) & ~(CELL_HEIGHT-1)) - spriteBBTop;
ySpeed = 0;
}
}
if (top_left == 0 and top_right != 0){
if (top_right_slide_left == 0) {
if (!input_right) && (!place_meeting(x-2, y, oParWall)) {
x -= 2;
}
y = ((bbox_top + CELL_HEIGHT) & ~(CELL_HEIGHT-1)) - spriteBBTop;
ySpeed = 0;
}
else {
y = ((bbox_top + CELL_HEIGHT) & ~(CELL_HEIGHT-1)) - spriteBBTop;
ySpeed = 0;
}
}
}
}
#endregion
x += xSpeed;
//COMMIT TO CHANGES IN X COORDINATES
//apply xsp value to x coordinate
#region Tile Collisions on the X-Axis
//Moving Right
if (xSpeed > 0) {
//return some tile map info
var top_right = tilemap_get_at_pixel(tilemap, bbox_right, bbox_top) & tile_index_mask;
var bot_right = tilemap_get_at_pixel(tilemap, bbox_right, bbox_bottom) & tile_index_mask;
//Slide checking
var top_right_slide_down = tilemap_get_at_pixel(tilemap, bbox_right, bbox_top + width_slide_distance) & tile_index_mask; //tile 5 pixels below?
var bot_right_slide_up = tilemap_get_at_pixel(tilemap, bbox_right, bbox_bottom - width_slide_distance) & tile_index_mask;
//tile on both corners, then stop
if (top_right != 0 and bot_right != 0) {
x = ((bbox_right & ~(CELL_WIDTH-1)) - 1) - spriteBBRight;
xSpeed = 0;
}
else {
if (top_right != 0 and bot_right == 0){ //tile at top right, but not bottom right, so check below top right corner
if (top_right_slide_down == 0) { // no tile present below top right then slide
if (!input_up) && (!place_meeting(x, y+2, oParWall)) {
y += 2;
}
x = ((bbox_right & ~(CELL_WIDTH-1)) - 1) - spriteBBRight;
xSpeed = 0;
}
else {
x = ((bbox_right & ~(CELL_WIDTH-1)) - 1) - spriteBBRight;
xSpeed = 0;
}
}
if (top_right == 0 and bot_right !=0 ) {
if (bot_right_slide_up == 0){
if (!input_down) && (!place_meeting(x, y-2, oParWall)) {
y -= 2;
}
x = ((bbox_right & ~(CELL_WIDTH-1)) - 1) - spriteBBRight;
xSpeed = 0;
}
else {
x = ((bbox_right & ~(CELL_WIDTH-1)) - 1) - spriteBBRight;
xSpeed = 0;
}
}
}
//Moving Left
} else {
var top_left = tilemap_get_at_pixel(tilemap, bbox_left, bbox_top) & tile_index_mask;
var bot_left = tilemap_get_at_pixel(tilemap, bbox_left, bbox_bottom) & tile_index_mask;
//Slide checking
var top_left_slide_down = tilemap_get_at_pixel(tilemap, bbox_left, bbox_top + width_slide_distance) & tile_index_mask; //tile 5 pixels above?
var bot_left_slide_up = tilemap_get_at_pixel(tilemap, bbox_left, bbox_bottom - width_slide_distance) & tile_index_mask;
//if tile present on both corners, then stop
if (top_left != 0 and bot_left != 0) {
x = ((bbox_left + CELL_WIDTH) & ~(CELL_WIDTH-1)) - spriteBBLeft;
xSpeed = 0;
}
else {
if (top_left != 0 and bot_left == 0){ //tile at top left, but not bottom left, so check below top left corner
if (top_left_slide_down == 0) { // no tile present below top left corner then slide
if (!input_up) && (!place_meeting(x, y+2, oParWall)) {
y += 2;
}
x = ((bbox_left + CELL_WIDTH) & ~(CELL_WIDTH-1)) - spriteBBLeft;
xSpeed = 0;
}
else {
x = ((bbox_left + CELL_WIDTH) & ~(CELL_WIDTH-1)) - spriteBBLeft;
xSpeed = 0;
}
}
if (top_left == 0 and bot_left !=0 ) { // tile present at the bottom left but not the top left
if (bot_left_slide_up == 0){
if (!input_down) && (!place_meeting(x, y-2, oParWall)) {
y -= 2;
}
x = ((bbox_left + CELL_WIDTH) & ~(CELL_WIDTH-1)) - spriteBBLeft;
xSpeed = 0;
}
else {
x = ((bbox_left + CELL_WIDTH) & ~(CELL_WIDTH-1)) - spriteBBLeft;
xSpeed = 0;
}
}
}
}
#endregion