• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Alternative collision system has hickup (SOLVED)

N

NeZvers

Guest
I wanted to make alternative collision check for movements that don't involve while loop and end movements in one frame.
I found out that checking bbox side values turns out unstable (whatever what amount offset I tried it either goes into a wall or stays away), so I hardcoded offsets and that part works.
But I have a problem when next step will be inside and player obj isn't already next to the wall - player obj is hickupping for 1-2 frames before standing where it should have been (next to a wall).

here's my step event (GMS2), maybe someone can chime in and point out what's causing this isse.
Code:
// Input check
var hinput = keyboard_check(vk_right)-keyboard_check(vk_left);
var vinput = keyboard_check(vk_down)-keyboard_check(vk_up);

//Horizontal speed
if(hinput!=0){
    hspd += hinput * 1;
    hspd=clamp(hspd,-4,4);
} else {hspd=0;}

//vertical speed
if(vinput!=0){
    vspd+=vinput*1;
    vspd=clamp(vspd,-4,4);
} else {vspd=0;}

//horizontal collision
if(place_meeting(x+hspd,y,oSolid)){
    var solid_ = instance_position(x+hspd,y,oSolid);
    if(hspd>0){
        with(solid_){other.x= x + other.ml;} //ml = offset needed to be moved left
           
    } else {
        with(solid_){other.x=x+15 + other.mr;} //mr = offset needed to be moved right
    }
    hspd=0;
}
x+=hspd;

//Vertical collision
if(place_meeting(x,y+vspd,oSolid)){
    var solid_ = instance_position(x,y+vspd,oSolid);
   
    if(vspd>0){
        with(solid_){other.y= y + other.mu;} //move up
           
    } else {
        with(solid_){other.y=y+15 + other.md;} //move down
    }
    vspd=0;
}
y+=vspd;

//clamp to room
x=clamp(x,0,room_width);
y=clamp(y,0,room_height);
 
Is there a particular reason you don't want to use while loops for collision? They are useful as it allows you to step one pixel at a time until collided, aka pixel perfect collision.
Also, with what you have right now, you're letting the solid blocks control where your character moves, that's a bit strange. You could achieve the same thing without the use of "with"
 

Miradur

Member
Hi, you add hspeed(hspd += hinput * 1) BEFORE the collision query and during the collision query,
you query x+hspeed(x+hspd,y,oSolid) again.
This will cause you to lose a maximum of 4 pixels(clamp), which you DO NOT query.
The same applies of course to y.


Miradur
 
N

NeZvers

Guest
@shadowspear1 I'm not satisfied with traditional while loop because for one if something goes wrong game freezes and you are not able to reset game to do another round of testing and for a second reason if you have movement using acceleration (below a value of 1) or lerping you won't get pixel perfect collision resulting not really pixel perfect collision. I guess in acceleration case I could use acceleration value * sign(hspd) inside while loop to get pixel perfect position but that won't help if there's something else wrong and can cause a freeze.
I tried using solid_.x / solid_.bbox_left etc. but that gave me an error that variable isn't defined. So only way I knew was to use with() function to get oSolid position and set position next to it which works but with weird hickup for 1-2 frames when the player stops remaining movement apart and then approaches side.


@Miradur I'm not sure what you mean because I set hspd and vspd only once and querying next position for collision (just the same way as it's done with traditional while loop method) and if next position is collision I have instance_position() to give me object I'm going to collide and after putting character right beside wall I don't need speed so I set it to 0. So in case, I'm not colliding hspd works like it should and sets position. If I'm not colliding hspd gets full speed.
 
I just noticed you're using instance_position (checks a single point) instead of instance_place (uses the calling object's collision box). Since you used place_meeting in the previous line, instance_position is probably returning -1 (undefined) since it couldn't find an oSolid at the point you gave it — that would explain why solid_.x / solid_.bbox_left was throwing an error before. Try using instance_place and see what happens
Code:
var solid_ = instance_place(x+hspd,y,oSolid);
 
T

TimothyAllen

Guest
I would suggest using a collision map approach if you are going to doing collisions that are aligned to a grid... it will be faster.

But if you want to stick with objects and using masks, why not move, THEN check for collision. Something like:
Code:
var c;

x += hspd;
c = instance_place(x, y, oSolid);

if (c != noone)
{
    if (hspd > 0)
    {
        x -= bbox_right - c.bbox_left + 1;
    }
    else
    {
        x += c.bbox_right - bbox_left + 1;
    }
 
    hspd = 0;
}

y += vspd;
c = instance_place(x, y, oSolid);

if (c != noone)
{
    if (vspd > 0)
    {
        y -= bbox_bottom - c.bbox_top + 1;
    }
    else
    {
        y += c.bbox_bottom - bbox_top + 1;
    }
 
    vspd = 0;
}
EDIT: Or if you want to set an an exact integer position on collision (to avoid bugs with rouding the bbox_ values of player) then try:
Code:
var c;

x += hspd;
c = instance_place(x, y, oSolid);

if (c != noone)
{
    x = hspd > 0 ? c.bbox_left - sprite_width + sprite_xoffset : c.bbox_right + sprite_xoffset + 1;
    // OR: if your sprite_bbox values altered
    //  x = hspd > 0 ? c.bbox_left - sprite_get_bbox_right(sprite_index) + sprite_xoffset - 1 : c.bbox_right + sprite_xoffset - sprite_get_bbox_left(sprite_index) + 1;
    hspd = 0;
}

y += vspd;
c = instance_place(x, y, oSolid);

if (c != noone)
{
    y = vspd > 0 ? c.bbox_top - sprite_height + sprite_yoffset : c.bbox_bottom + sprite_yoffset + 1;
    vspd = 0;
}
 
Last edited by a moderator:
N

NeZvers

Guest
@TimothyAllen Dude, your last one works PERFECTLY like I wanted. I was just exploring what other collision options there are and my starting idea was almost there and got me frustrated.
Can you please explain what your line does:
Code:
x = hspd > 0 ? c.bbox_left - sprite_width + sprite_xoffset : c.bbox_right + sprite_xoffset + 1;
What > does in setting value and same for "?" and ":" ?
EDIT: did some digging and understood that it's inline expression and could be interpreted as
Code:
if (hspd > 0){
   x = c.bbox_left - sprite_width + sprite_xoffset;
} else {
   x=c.bbox_right + sprite_xoffset + 1;
}
 
Last edited:
T

TimothyAllen

Guest
@TimothyAllen Dude, your last one works PERFECTLY like I wanted. I was just exploring what other collision options there are and my starting idea was almost there and got me frustrated.
Can you please explain what your line does:
Code:
x = hspd > 0 ? c.bbox_left - sprite_width + sprite_xoffset : c.bbox_right + sprite_xoffset + 1;
What > does in setting value and same for "?" and ":" ?
EDIT: did some digging and understood that it's inline expression and could be interpreted as
Code:
if (hspd > 0){
   x = c.bbox_left - sprite_width + sprite_xoffset;
} else {
   x=c.bbox_right + sprite_xoffset + 1;
}
You are correct... it its probably more readable that way.
 
N

NeZvers

Guest
Yeah, but thanks to you I learned awesome code "technique" and I'll be using it a lot :D same as % operator. I freaking love these!
Now I can strike out the bounding box collision from my learning list. Next I have to check your suggested "collision map" technique but it seems that my favorite, for now, is bbox approach because there's no while loop and collision is TRUE pixel perfect collision.
 
Top