• 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!

Grid based collision detection glitch

A

AnimusRex

Guest
So, I'm following HeartBeast's tutorial for randomly generating a grid based level. Everything up until the movement has worked fine.

The way I'm having movement work is comparable to old-school Resident evil games; you turn left and right on the spot, and the up arrow key is what moves your character forward. As this is a tile-based Roguelike, there are 8 cardinal directions you can go.

With that explained, here is the code I have for "grid_place_meeting"
Code:
///Checking collisions
var xx = argument[0];
var yy = argument[1];

//Remember player position
var xp = x;
var yp = y;

//Update position for the mask calculations
x = xx;
y = yy;

//Check for an x meeting on the grid in either left or right according to the sprites bounding box
var x_meeting = (Level.grid[# bbox_right div CELL_WIDTH, bbox_top div CELL_HEIGHT] != FLOOR) ||
                (Level.grid[# bbox_left div CELL_WIDTH, bbox_top div CELL_HEIGHT] != FLOOR);

//Check for a y meeting on the grid in either top or bottom according to the sprites bounding box          
var y_meeting = (Level.grid[# bbox_right div CELL_WIDTH, bbox_bottom div CELL_HEIGHT] != FLOOR) ||
                (Level.grid[# bbox_left div CELL_WIDTH, bbox_bottom div CELL_HEIGHT] != FLOOR);
            
//Move back if collided
x = xp;
y = yp;

//Return true or false
return x_meeting or y_meeting;
And here is the code I have for movement.

Code:
var speedx = argument [0];
var speedy = argument [1];

//Horizontal Collisions
if (grid_place_meeting(x+speedx, y)) {
    while (!grid_place_meeting(x+sign(speedx), y)) {
        x+= sign(speedx);
    }
    speedx = 0;
}

//Vertical Collisions
if (grid_place_meeting(x, y+speedy)) {
    while (!grid_place_meeting(x, y+sign(speedy))) {
        y+= sign(speedy);
    }
    speedy = 0;
}

//Setting up animation frames
if imageNumber == 1 {image_index = 1}
if imageNumber == 2 {image_index = 2}
if imageNumber == 3 {image_index = 3}
if imageNumber == 4 {image_index = 4}
if imageNumber == 5 {image_index = 5}
if imageNumber == 6 {image_index = 6}
if imageNumber == 7 {image_index = 7}

//Code for turning on the spot
if (ismoving == false)
    {
        if (keyboard_check_pressed(vk_right))
        {
            image_index += 1;
        }
        if (keyboard_check_pressed(vk_left))
        {
            image_index -= 1;
        }

if (keyboard_check(vk_up))
        {
        if image_index = 0 //Moving North
            {
            ismoving = true;
            movetimer = 32;
            speedy = -movespeed;
            speedx = 0;
            }
        if image_index = 1 //Moving North East
            {
            ismoving = true;
            movetimer = 32;
            speedy = -movespeed;
            speedx = movespeed;
            }
        if image_index = 2 //Moving East
            {
            ismoving = true;
            movetimer = 32;
            speedy = 0;
            speedx = movespeed;
            }
        if image_index = 3 //Moving South-East
            {
            ismoving = true;
            movetimer = 32;
            speedy = movespeed;
            speedx = movespeed;
            }
        if image_index = 4 //Moving South
            {
            ismoving = true;
            movetimer = 32;
            speedy = movespeed;
            speedx = 0;
            }
        if image_index = 5 //Moving South-West
            {
            ismoving = true;
            movetimer = 32;
            speedy = movespeed;
            speedx = -movespeed;
            }
        if image_index = 6 //Moving West
            {
            ismoving = true;
            movetimer = 32;
            speedy = 0;
            speedx = -movespeed;
            }
        if image_index = 7 //Moving North-West
            {
            ismoving = true;
            movetimer = 32;
            speedy = -movespeed;
            speedx = -movespeed;
            }
        }
    }

if (ismoving == true)
    {
        y += speedy;
        x += speedx;
        movetimer -= movespeed
        if (movetimer == 0) ismoving = false;
    }
I'm not using snapping commands for the grid movement, but rather a timer that allows 32 pixels of movement time. The grid based movement works fine, until I try to enable the collision detection, whereupon I can move 1 pixel in any direction at a time.

I'm sure my math is wrong for this somewhere, and I'm dividing 32 by 32 and ending up with 1, but I can't for the life of me see where. Any help appreciated!

EDIT:

After looking at the code more and fiddling with the character sprites, I've determined that I'm moving 4 pixels per input of the up arrow, but no collision detection is taking place between the walls and the player character in any direction.

If I have simple movement, I can do collision detection. If I don't do collision detection, my 8 directional grid-based movement works fine.

I guess I'll try to put a collision check into the movement key itself rather than check the script, see if that does anything...
 
Last edited by a moderator:

jo-thijs

Member
Your collision code is fine, but you reset speedx and speedy in the code below it and thereafter you use:
y += speedy;
x += speedx;

This makes your collision code useless.
The collision code should be executed just before the if (ismoving == true).
 
A

AnimusRex

Guest
I'm not really sure how you mean. As well, to use the collision code before the ismoving variable, are you saying to have all of
Code:
if (grid_place_meeting(x+speedx, y)) {
    while (!grid_place_meeting(x+sign(speedx), y)) {
        x+= sign(speedx);
    }
    speedx = 0;
}
Just before
Code:
if image_index = 0 //Moving North
            {
            ismoving = true;
            movetimer = 32;
            speedy = -movespeed;
            speedx = 0;
            }
For example?

Wouldn't this be a ton of extra lines as I'd have to do it before each of the 8 directions, and again for moving backwards? As well, I'm already not sure how I would be using this code for the 4 diagonals, as I would have to check
Code:
grid_place_meeting(x+speedx, y+speedy))
I suppose, but I have a feeling it's not going to work, as the collision code is based on a more simplistic movement code than what I have created.
 

jo-thijs

Member
No, I'm saying to have it like this:
Code:
var speedx = argument [0];
var speedy = argument [1];

//Setting up animation frames
if imageNumber == 1 {image_index = 1}
if imageNumber == 2 {image_index = 2}
if imageNumber == 3 {image_index = 3}
if imageNumber == 4 {image_index = 4}
if imageNumber == 5 {image_index = 5}
if imageNumber == 6 {image_index = 6}
if imageNumber == 7 {image_index = 7}

//Code for turning on the spot
if (ismoving == false)
    {
        if (keyboard_check_pressed(vk_right))
        {
            image_index += 1;
        }
        if (keyboard_check_pressed(vk_left))
        {
            image_index -= 1;
        }

if (keyboard_check(vk_up))
        {
        if image_index = 0 //Moving North
            {
            ismoving = true;
            movetimer = 32;
            speedy = -movespeed;
            speedx = 0;
            }
        if image_index = 1 //Moving North East
            {
            ismoving = true;
            movetimer = 32;
            speedy = -movespeed;
            speedx = movespeed;
            }
        if image_index = 2 //Moving East
            {
            ismoving = true;
            movetimer = 32;
            speedy = 0;
            speedx = movespeed;
            }
        if image_index = 3 //Moving South-East
            {
            ismoving = true;
            movetimer = 32;
            speedy = movespeed;
            speedx = movespeed;
            }
        if image_index = 4 //Moving South
            {
            ismoving = true;
            movetimer = 32;
            speedy = movespeed;
            speedx = 0;
            }
        if image_index = 5 //Moving South-West
            {
            ismoving = true;
            movetimer = 32;
            speedy = movespeed;
            speedx = -movespeed;
            }
        if image_index = 6 //Moving West
            {
            ismoving = true;
            movetimer = 32;
            speedy = 0;
            speedx = -movespeed;
            }
        if image_index = 7 //Moving North-West
            {
            ismoving = true;
            movetimer = 32;
            speedy = -movespeed;
            speedx = -movespeed;
            }
        }
    }

//Horizontal Collisions
if (grid_place_meeting(x+speedx, y)) {
    while (!grid_place_meeting(x+sign(speedx), y)) {
        x+= sign(speedx);
    }
    speedx = 0;
}

//Vertical Collisions
if (grid_place_meeting(x, y+speedy)) {
    while (!grid_place_meeting(x, y+sign(speedy))) {
        y+= sign(speedy);
    }
    speedy = 0;
}

if (ismoving == true)
    {
        y += speedy;
        x += speedx;
        movetimer -= movespeed
        if (movetimer == 0) ismoving = false;
    }
The problem is, when colliding with a wall, you set speedx and speedy to 0 to prevent the player from moving inside.
However, directly afterwards, you do a bunch of these:
Code:
        if image_index = 0 //Moving North
            {
            ismoving = true;
            movetimer = 32;
            speedy = -movespeed;
            speedx = 0;
            }
which reset speedx and speedy to move through walls.
After that you do the actual movement, ignoring the changes the collision code made to speedx and speedy.
 
A

AnimusRex

Guest
So should I have the collision code put the movetimer to 0 instead of speedx and speedy?

As it is, it's not just ignoring walls, it moves at 4 pixels per key hold even with floor tiles in all 9 directions. So it must be a problem with the collision code, as when I put it in, it's malfunctioning, yes, but not only when it's near wall tiles.

Do bbox commands work with an altered hitbox for my main sprite? I'm on a 32x32 grid but my character is 64 pixels tall. I edited the collision mask for the sprite to be his 32x32 bottom, but I'm really not sure how the bbox commands work. Regardless I'll be changing my sprite to a 32x32 box with cardinal directions just to bug test I suppose.

I've also tried arranging the script the way you suggested, but it halts movement altogether.

EDIT: Solved it. Not sure which fix it was, as I've been swapping variables all over the place. I think It's because I did
Code:
        y+= sign(speedy);
    }
    ismoving = false
    speedy = 0;
}
Or it could be something to do with the bbox commands with my larger sprite.

So; it's "solved" in that it's working, but not working perfectly.

The problem now is that in moving north-east, for example, if there's a wall only to the east, you should move up one square. I'll tinker with it a bit, when I inevitably screw it up entirely I guess I'll open a new thread :D

Thanks a lot Jo.
 
Last edited by a moderator:
D

DevNorway

Guest
Code:
if imageNumber == 1 {image_index = 1}
if imageNumber == 2 {image_index = 2}
if imageNumber == 3 {image_index = 3}
if imageNumber == 4 {image_index = 4}
if imageNumber == 5 {image_index = 5}
if imageNumber == 6 {image_index = 6}
if imageNumber == 7 {image_index = 7}
You could definitely just do all that in one command.
Code:
image_index = imageNumber;
 
A

AnimusRex

Guest
And it's for things like that I come to these forums. Thanks a lot, man!
 
Top