• Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

Question - Code Tileset Collision Problem

R

Reaxgrim

Guest
Ok. am new to gm2 and gml altogether.
But was going along with how gm_wolf does his tileset collision and came across a slight problem.

I am using a 16x16 collision tileset.

basically if falling from a decent height or just randomly when jumping around like a madman my little guy goes straight through the collision tileset.
I am thinking that its not detecting the collision fast enough?

gif of problem below. and the code. (ps: sorry if my codes a mess as i said. new to gml)

colproblem.gif

And the code.

CREATE ------

Code:
cursor_sprite = spr_cursoro;
window_set_cursor(cr_none);


//Player Camera creation

//Build Player Camera Defaults
camera = camera_create_view(0, 0, 1152, 648, 0, -1, -1, -1, 700, 700);

//Set view0 to use the camera "camera"
view_set_camera(0, camera);

//Setting up object target information
camera_set_view_target(camera,obj_Player);
camera_set_view_speed(view_camera[0], -1, -1);
camera_set_view_border(view_camera[0], 700, 700);


//Basic Player Vars
move_speed = 5;
jump_impulse = 11;
can_djump = false;
grav = 0.75;
v_speed = 0;


//Tilemap Info
var c1 = layer_get_id("collision_layer");
tilemap = layer_tilemap_get_id(c1);


//Sprite Info
sprite_bbox_left = sprite_get_bbox_left(sprite_index) - sprite_get_xoffset(sprite_index);
sprite_bbox_right = sprite_get_bbox_right(sprite_index) - sprite_get_xoffset(sprite_index);
sprite_bbox_bottom = sprite_get_bbox_bottom(sprite_index) - sprite_get_yoffset(sprite_index);
sprite_bbox_top = sprite_get_bbox_top(sprite_index) - sprite_get_yoffset(sprite_index);


STEP -----

Code:
// Jump Impulse, Top Collision Check
// Contact Points
var t1 = tilemap_get_at_pixel(tilemap,bbox_left,bbox_bottom + 1)& tile_index_mask;
var t2 = tilemap_get_at_pixel(tilemap,bbox_right,bbox_bottom + 1)& tile_index_mask;

//Tile ID checking
if (t1 != 0 || t2 != 0) {

    if (keyboard_check_pressed(vk_space)) {

    v_speed = -jump_impulse;
    can_djump = true;

    }
    
} else {

    if (keyboard_check_pressed(vk_space) & can_djump != false) {

    v_speed = -jump_impulse;
    can_djump = false;
    
    }
}

var dx = move_speed * (keyboard_check(ord("D")) - keyboard_check(ord("A")));
var dy = v_speed;
v_speed += grav;

    if (keyboard_check(ord("D"))) {
        image_xscale = 1;
        
    } else if (keyboard_check(ord("A"))) {
        image_xscale = -1;   
    }


// Vertical Move, Bottom Collision Check

y += dy;

    

if (dy > 0) {
    // Contact Points
    var t1 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_bottom) & tile_index_mask;
    var t2 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_bottom) & tile_index_mask;
    
    //Tile ID checking
    if (t1 == 1 || t2 == 1) {
    
        y = ((bbox_bottom & ~15) - 1) - sprite_bbox_bottom;
        v_speed = 0;
    }
    

} else {
    // Contact Points
    var t1 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_top) & tile_index_mask;
    var t2 = tilemap_get_at_pixel(tilemap, bbox_right,bbox_top) & tile_index_mask;
    
    //Tile ID checking
    if (t1 == 1 || t2 == 1) {
    
        y = ((bbox_top + 16) & ~15) - sprite_bbox_top;
        v_speed = 0;
    
    }
}


// Horizontal Movement, Left/Right Collision Check

x += dx;

if (dx > 0) { // Right Move

    sprite_index = spr_Bloo;
// Contact Points
    var t1 = tilemap_get_at_pixel(tilemap, bbox_right, bbox_top) & tile_index_mask;
    var t2 = tilemap_get_at_pixel(tilemap, bbox_right,bbox_bottom) & tile_index_mask;
    
//Tile ID checking
    if (t1 == 1 || t2 == 1) {
    
    x = ((bbox_right & ~15) - 1) - sprite_bbox_right;
    }

    } else if (dx == 0) {
        sprite_index = spr_Bloo_Idle;
    }
    else { // Left Move
        sprite_index = spr_Bloo;
// Contact Points   
        var t1 = tilemap_get_at_pixel(tilemap, bbox_left, bbox_top) & tile_index_mask;
        var t2 = tilemap_get_at_pixel(tilemap, bbox_left,bbox_bottom) & tile_index_mask;
    
//Tile ID checking
        if (t1 == 1 || t2 == 1) {
    
            x = ((bbox_left + 16) & ~15) - sprite_bbox_left;
        }
}

Any ideas/thought would be great.
Cheers
- Reax.
 

csanyk

Member
If you cap your falling speed, it most likely will not fall through so many tiles before checking one.

It looks to me like it's accelerating and by the time it reaches the ground, it's already moving at a speed faster than 16px/step, so it's skipping through a few layers of tile before it checks for the next collision, and ends up buried.

This commonly happens at speeds higher than the size of the collision mask.

You can handle it in a few ways:
  1. clamp speed to sprite_size, and accept that falling is going to be a bit slow.
  2. clamp speed to sprite_size, and increase room_speed while reducing other speeds proportionately so that everything still feels right.
  3. If speed > sprite_size, manually check for a collision every sprite_size pixels between x_current, y_current and x_next, y_next before committing the move, and if there's a collision, position the moving instance adjacent to the object it would collide with, set speed = 0, and on_ground = true.
  4. Regard it as a happy discovery, and build a game mechanic around it. It's somewhat comical that this character ends up buried in the ground like that. It could be put to good use. Daniel Linssen's The Sun and Moon does pretty much exactly this, and is an excellent game.
 

Chaser

Member
Might be something in your step event, as your character is falling, it looks like it's speed is increasing, so maybe set a max speed for your falling speed then the step event should check it better for a collision event. I may be wrong, I'm not a pro at gamemaker either, just a suggestion really.im sure someone else will come along and help.
 

GMWolf

aka fel666
If speed > sprite_size, manually check for a collision every sprite_size pixels between x_current, y_current and x_next, y_next before committing the move, and if there's a collision, position the moving instance adjacent to the object it would collide with, set speed = 0, and on_ground = true.
I think this is probably the best solution.
An easy way to implement that would be to have a loop to repeat the collision code, setting dy such that it would be the remaining vspeed or image_height

Something like:
Code:
var remain = v_speed;
while(remain > 0){
 var dy = min(image_height, v_speed);
 remain -= image_height;

 //Move by dy and collide
}
I also noticed you have (t1 == 1 || t2 == 1)
This means you can only collide with tile index 1. If you want to collide with all non empty tiles, you should use (t1 != 0 || t2 != 0)
 
R

Reaxgrim

Guest
I also noticed you have (t1 == 1 || t2 == 1)
This means you can only collide with tile index 1. If you want to collide with all non empty tiles, you should use (t1 != 0 || t2 != 0)
Yeah i was using 1 as collision / 2 as death on touch etc but only had it set to 1 for testing just now. making sure i can get it working first :)
 

GMWolf

aka fel666
Yeah i was using 1 as collision / 2 as death on touch etc but only had it set to 1 for testing just now. making sure i can get it working first :)
Ah yes, for a moment i forgot I used a separate map to the aestetic one for collisions in the tutorial ^^ It really is much easier that way :)
 

Posh Indie

Member
If you cap your falling speed, it most likely will not fall through so many tiles before checking one.

It looks to me like it's accelerating and by the time it reaches the ground, it's already moving at a speed faster than 16px/step, so it's skipping through a few layers of tile before it checks for the next collision, and ends up buried.

This commonly happens at speeds higher than the size of the collision mask.

You can handle it in a few ways:
  1. clamp speed to sprite_size, and accept that falling is going to be a bit slow.
  2. clamp speed to sprite_size, and increase room_speed while reducing other speeds proportionately so that everything still feels right.
  3. If speed > sprite_size, manually check for a collision every sprite_size pixels between x_current, y_current and x_next, y_next before committing the move, and if there's a collision, position the moving instance adjacent to the object it would collide with, set speed = 0, and on_ground = true.
  4. Regard it as a happy discovery, and build a game mechanic around it. It's somewhat comical that this character ends up buried in the ground like that. It could be put to good use. Daniel Linssen's The Sun and Moon does pretty much exactly this, and is an excellent game.
It's not a bug, it's a feature, haha. I never heard of that game before, but it's actually quite brilliant.
 
R

Reaxgrim

Guest
Just clamped it to the size of the sprite when downwards, and doubled it going up so my guy can still jump normally.
Code:
v_speed = clamp(v_speed,-32,16);
no idea if its the best way but it works so i guess it will do :)
 
Top