SOLVED Tile collision

junixbr

Member
I'm having a hard time running a small tile collision system.
The lateral (horizontal) collisions are perfect, the negative vertical collision too, but I cannot make the positive vertical collision work.
I don't know if it has any influence, but the game has infinite scroll (the screen does not depend on elements of the game to scroll).

GML:
#region moving
    move_right = (keyboard_check(vk_right)) || (keyboard_check(ord("D"))) || (gamepad_button_check(0, gp_padr)) || (gamepad_axis_value(0, gp_axislh) > 0);
    move_left = (keyboard_check(vk_left)) || (keyboard_check(ord("A"))) || (gamepad_button_check(0, gp_padl)) || (gamepad_axis_value(0, gp_axislh) < 0);
    move_up = (keyboard_check(vk_up)) || (keyboard_check(ord("W"))) || (gamepad_button_check(0, gp_padu)) || (gamepad_axis_value(0, gp_axislv) < 0);
    move_down = (keyboard_check(vk_down)) || (keyboard_check(ord("S"))) || (gamepad_button_check(0, gp_padd)) || (gamepad_axis_value(0, gp_axislv) > 0);
    
    // collisions
    input_direction = point_direction(0, 0, move_right - move_left, move_down - move_up);
    input_magnitude = (move_right - move_left != 0) || (move_down - move_up != 0);
    
    h_speed = lengthdir_x(input_magnitude * max_speed, input_direction);
    v_speed = lengthdir_y(input_magnitude * max_speed, input_direction);

    // horizontal
    if (tilemap_get_at_pixel(tilemap_colisions, x + h_speed, y)) {
        x -= x mod tile_size;
        if (sign(h_speed) == 1) {
            x += tile_size - 1;
            h_speed = 0;
        }
        if (sign(h_speed) == -1) {
            h_speed = 0;
        }
    }

    if (move_right) {
        image_xscale = 1;
        y -= 0.5;
    }
    if (move_left) {
        image_xscale = -1;
        y -= 0.5;
    }
    x += h_speed;

    // vertical
    if (tilemap_get_at_pixel(tilemap_colisions, x, y + v_speed)) {
    y -= y mod tile_size;
        if (sign(v_speed) == 1) {
            y += tile_size - 1;
            v_speed = 0;
        }
        if (sign(v_speed) == - 1) {
            y -= tile_size - 1;
            v_speed = 0;
        }
        if (sign(v_speed) == 0) {
            y += tile_size + 1;
            v_speed = 0;
        }
    }
    if (move_down) {
        if (!move_left && !move_right) {
            v_speed -= 1;
        }
    }
    y += v_speed;
    
    if (move_right || move_left || move_down || move_up) {
        sprite_index = spr_player_walking_top;
        player_botton.sprite_index = spr_player_walking_botton;
    }
    
    // idle
    if (global.screen_scrolling) {
        if (!move_right && !move_left && !move_up && !move_down) {
            // scrolling
            y -= 0.5;
        }
    }
#endregion
 

erayzesen

Member
Why don't you make this with while loop?

Check sides of the instance, learn side of the tile. For example the tile in the right side;

while( tilemap_get_at_pixel(tilemap_colisions,x+h_speed+bbox_right,y )!=false){
x-=1;
}

It's the clean and practic way.
 
Last edited:

junixbr

Member
I thought that I was making the easy way... lol
I have no idea how to implement using while, could you help me?
Sorry I'm a little bit noob in GMS2.
 

TheouAegis

Member
if (sign(v_speed) == 0)
Code:
   if (tilemap_get_at_pixel(tilemap_colisions, x, y + v_speed)) {
    y -= y mod tile_size;
        if (sign(v_speed) == 1) {
            y += tile_size - 1;
            v_speed = 0;
        }
        if (sign(v_speed) == - 1) {
            y -= tile_size - 1;
            v_speed = 0;
        }
        if (sign(v_speed) == 0) {
            y += tile_size + 1;
            v_speed = 0;
        }
    }
A part of this code does not belong. If you can't figure out which part doesn't belong, look at what I "quoted" for a hint.
 

junixbr

Member
Code:
   if (tilemap_get_at_pixel(tilemap_colisions, x, y + v_speed)) {
    y -= y mod tile_size;
        if (sign(v_speed) == 1) {
            y += tile_size - 1;
            v_speed = 0;
        }
        if (sign(v_speed) == - 1) {
            y -= tile_size - 1;
            v_speed = 0;
        }
        if (sign(v_speed) == 0) {
            y += tile_size + 1;
            v_speed = 0;
        }
    }
A part of this code does not belong. If you can't figure out which part doesn't belong, look at what I "quoted" for a hint.
I used sign(v_speed) == 0 to know when the player is 'idle', is not going to up or down.
But if it collides (in idle state), must be the correct behavior.
 

TheouAegis

Member
Okay, you missed a couple things then. So, your entire tile map is moving? There's no reason to check for a collision if neither party is actually moving. If your player is idle and not moving, and if the tile map is not moving, then there won't be any collision to detect. Secondly, you are checking if the speed is zero and then moving the instance if so. One line above that, your setting the speed to 0. Three lines above that you are setting v_speed to 0. So even if for whatever reason you still need or just want to keep a collision check when v_speed is 0, you need to modify that code so you aren't checking if v_speed is 0 in the same step that you set v_speed to 0.
 

junixbr

Member
Okay, you missed a couple things then. So, your entire tile map is moving? There's no reason to check for a collision if neither party is actually moving. If your player is idle and not moving, and if the tile map is not moving, then there won't be any collision to detect. Secondly, you are checking if the speed is zero and then moving the instance if so. One line above that, your setting the speed to 0. Three lines above that you are setting v_speed to 0. So even if for whatever reason you still need or just want to keep a collision check when v_speed is 0, you need to modify that code so you aren't checking if v_speed is 0 in the same step that you set v_speed to 0.
Yes, my entire tile map is moving all the time as you can see in this video:
Sign(v_speed) is not the player speed, this is the direction. If is positive, the player is going up, negative... down and zero is 'idle', but this idle is v_speed = -0.5. I need this to the player follow the tile map.
The reason to change v_speed to 0 in the collision moment, is to doesn't allow the player goes inside the tile collision block. (this is my intention, but must probably I'm doing wrong way)
My curious is the horizontal collinsion works fine and I'm trying to understand why the vertical is not the same behavior.
 

TheouAegis

Member
Because you don't have a condition for when h_speed is 0. you have one extra condition that you are using for vertical movement.

Put else in between your conditionals.
 

junixbr

Member
Because you don't have a condition for when h_speed is 0. you have one extra condition that you are using for vertical movement.

Put else in between your conditionals.
Thank you TheouAegis, I removed this condition, but now the problem change side.
Now from up to down is working (v_speed positive), but down to up is jumping the obstacle (v_speed negative).

GML:
    // horizontal
    if (tilemap_get_at_pixel(tilemap_colisions, x + h_speed, y)) {
        x -= x mod tile_size;
        if (sign(h_speed) == 1) {
            x += tile_size - 1;
            h_speed = 0;
        }
        if (sign(h_speed) == -1) {
            h_speed = 0;
        }
    }

    if (move_right) {
        image_xscale = 1;
        y -= 0.5;
    }
    if (move_left) {
        image_xscale = -1;
        y -= 0.5;
    }
    x += h_speed;

    // vertical
    if (tilemap_get_at_pixel(tilemap_colisions, x, y + v_speed)) {
        y -= y mod tile_size;
        if (sign(v_speed) == 1) {
            y += tile_size - 1;
            v_speed = 0;
        }
        if (sign(v_speed) == - 1) {
            y -= tile_size + 1;
            v_speed = 0;
        }
    }
    if (move_down) {
        if (!move_left && !move_right) {
            v_speed -= 1;
        }
    }
    y += v_speed;
 
Top