0
\$\begingroup\$

I'm coding a 3D game for a project using OpenGL and I'm trying to do tile collision on a surface.

The surface plane is split into a grid of 64x64 pixels and I can simply check if the (x,y) tile is empty or not.

Besides having a grid for collision, there's still free movement inside a tile.

For each entity, in the end of the update function I simply increase the position by the velocity:

pos.x += v.x;
pos.y += v.y;

I already have a collision grid created but my collide function is not great, i'm not sure how to handle it. I can check if the collision occurs but the way I handle is terrible.

int leftTile = repelBox.x / grid->cellSize;
int topTile = repelBox.y / grid->cellSize;
int rightTile = (repelBox.x + repelBox.w) / grid->cellSize;
int bottomTile = (repelBox.y + repelBox.h) / grid->cellSize;

for (int y = topTile; y <= bottomTile; ++y)
{
    for (int x = leftTile; x <= rightTile; ++x)
    {

        if (grid->getCell(x, y) == BLOCKED){
            Rect colBox = grid->getCellRectXY(x, y);
            Rect xAxis = Rect(pos.x - 20 / 2.0f, pos.y - 20 / 4.0f, 20, 10);
            Rect yAxis = Rect(pos.x - 20 / 4.0f, pos.y - 20 / 2.0f, 10, 20);

            if (colBox.Intersects(xAxis))
                v.x *= -1;

            if (colBox.Intersects(yAxis))
                v.y *= -1;


        }
    }
}

If instead of reversing the direction I set it to false then when the entity tries to get away from the wall it's still intersecting the tile and gets stuck on that position.

EDIT: I've worked with Flashpunk and it has a great function for movement and collision called moveBy. Are there any simplified implementations out there so I can check them out?

EDIT2: I've figured out a solution, you can check the answer below

\$\endgroup\$
1
\$\begingroup\$

There are two ways you can perform collision detection:

  1. Check in advance whether there's a collision, then move
  2. First move, then check whether we're in collision and correct our position

I'm not sure which way you're doing it, but given the fact you've said the entity is still intersecting the tile, I'm assuming it's the latter.

If so, try correcting the entity's position so that it doesn't intersect anymore. E.g. snap the entity to tile's borders, when it will try to cross it.

OpenGL does not have collision detection functionality. You could try using something more high-level like Ogre3D or low(er)-level like SDL. They should make your life a bit easier.

\$\endgroup\$
0
\$\begingroup\$

I solved it for now.

You can use that code in your programs to check for grid collision and allowing free movement inside a tile. I already have a grid created with tile info already there. Here's the code:

XY vertical = XY(0, 1);
XY horizontal = XY(1, 0);
XY diagonal = XY(1, 1);

void Entity::moveBy(float x, float y){
vec2f direccao = vec2f((x > 0) ? 1 : -1, (y > 0) ? 1 : -1); // direction vector

Rect newBoundingBox = Rect(pos.x + x - 20 / 2.0f, pos.y + y - 20 / 2.0f, 20, 20); // new bounding box for future position (future position = x + velocity.x

XY playerCell = XY((int)(pos.x / grid->cellSize), (int)(pos.y / grid->cellSize)); // get the cell the player is in giving the world pos. Eg: 38, 20

XY vert = direccao * vertical; // multiply direction vector with vertical vector = (dir.x * vert.x, dir.y * vert.y)
XY hori = direccao * horizontal; // multiply direction vector with horizontal vector = (dir.x * hori.x, dir.y * hori.y)

//this will get the cell in the vertical axis that the entity can collide
vert = vert + playerCell; // vert = (vert.x + playerCell.x, vert.y + playerCell.y)
hori = hori + playerCell; //repeat previous operation for horizontal axis

// if blocked vertical -> y
if (grid->getCell(vert.x, vert.y) == BLOCKED){
    Rect col = grid->getCellRectXY(vert.x, vert.y);
    if (!col.Intersects(newBoundingBox))  // simple AABB collision detection
        pos.y += y;

}
else
    pos.y += y;

// if blocked horizontal -> x
if (grid->getCell(hori.x, hori.y) == BLOCKED){
    Rect col = grid->getCellRectXY(hori.x, hori.y);
    if (!col.Intersects(newBoundingBox))
        pos.x += x;
}
else
    pos.x += x;

// not doing diagonal collision check for now

}

enter image description here

enter image description here

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.