1
\$\begingroup\$

I've been using LibGDX for the past few weeks and I have some problems that I need help on. What I need help on is understanding how to use LibGDX Rectangle class for a platformer.

I found this project on github that seems to be useful.

https://github.com/obviam/star-assault-reboot

I was able to wrap my mind around how this game worked for the most part.

The only thing I can't understand, which is the most essential part of the game, is how the collision detection and response works.

In the project, the BobController class holds the everything that's used to detect collision.

https://github.com/obviam/star-assault-reboot/blob/master/core/src/net/obviam/starassault/controller/BobController.java

I tried going to the website linked in the github project for answers, but it seems to be empty.

Maybe I'm just dumb, but I can't wrap my mind how this works. Even with the comments provided in the project, I still don't understand.

Can someone explain in greater detail how this class handles collision detection and response using the LibGDX Rectangle class.

EDIT:

This is the specific function that I don't understand:

/** Collision checking **/
private void checkCollisionWithBlocks(float delta) {
    // scale velocity to frame units 
    bob.getVelocity().scl(delta);

    // Obtain the rectangle from the pool instead of instantiating it
    Rectangle bobRect = rectPool.obtain();
    // set the rectangle to bob's bounding box
    bobRect.set(bob.getBounds().x, bob.getBounds().y, bob.getBounds().width, bob.getBounds().height);

    // we first check the movement on the horizontal X axis
    int startX, endX;
    int startY = (int) bob.getBounds().y;
    int endY = (int) (bob.getBounds().y + bob.getBounds().height);
    // if Bob is heading left then we check if he collides with the block on his left
    // we check the block on his right otherwise
    if (bob.getVelocity().x < 0) {
        startX = endX = (int) Math.floor(bob.getBounds().x + bob.getVelocity().x);
    } else {
        startX = endX = (int) Math.floor(bob.getBounds().x + bob.getBounds().width + bob.getVelocity().x);
    }

    // get the block(s) bob can collide with
    populateCollidableBlocks(startX, startY, endX, endY);

    // simulate bob's movement on the X
    bobRect.x += bob.getVelocity().x;

    // clear collision boxes in world
    world.getCollisionRects().clear();

    // if bob collides, make his horizontal velocity 0
    for (Block block : collidable) {
        if (block == null) continue;
        if (bobRect.overlaps(block.getBounds())) {
            bob.getVelocity().x = 0;
            world.getCollisionRects().add(block.getBounds());
            break;
        }
    }

    // reset the x position of the collision box
    bobRect.x = bob.getPosition().x;

    // the same thing but on the vertical Y axis
    startX = (int) bob.getBounds().x;
    endX = (int) (bob.getBounds().x + bob.getBounds().width);
    if (bob.getVelocity().y < 0) {
        startY = endY = (int) Math.floor(bob.getBounds().y + bob.getVelocity().y);
    } else {
        startY = endY = (int) Math.floor(bob.getBounds().y + bob.getBounds().height + bob.getVelocity().y);
    }

    populateCollidableBlocks(startX, startY, endX, endY);

    bobRect.y += bob.getVelocity().y;

    for (Block block : collidable) {
        if (block == null) continue;
        if (bobRect.overlaps(block.getBounds())) {
            if (bob.getVelocity().y < 0) {
                grounded = true;
            }
            bob.getVelocity().y = 0;
            world.getCollisionRects().add(block.getBounds());
            break;
        }
    }
    // reset the collision box's position on Y
    bobRect.y = bob.getPosition().y;

    // update Bob's position
    bob.getPosition().add(bob.getVelocity());
    bob.getBounds().x = bob.getPosition().x;
    bob.getBounds().y = bob.getPosition().y;

    // un-scale velocity (not in frame time)
    bob.getVelocity().scl(1 / delta);

    }
\$\endgroup\$
  • \$\begingroup\$ Is there a specific part that's confusing you? The question is a little broad. \$\endgroup\$ – John Dec 28 '16 at 20:55
  • \$\begingroup\$ Yeah, please include all the parts that are required to help you in the question, without us requiring to leave this site to understand. \$\endgroup\$ – Alexandre Vaillancourt Dec 28 '16 at 21:11
  • \$\begingroup\$ Just added the specific function I need help understanding. \$\endgroup\$ – Redt Dec 30 '16 at 19:24
2
\$\begingroup\$

Detecting a collision between two rectangles is relatively straightforward- if they overlap, they collide. libGDX provides this as part of the Rectangle.overlap() method:

public boolean overlaps (Rectangle r) { return x < r.x + r.width && x + width > r.x && y < r.y + r.height && y + height > r.y; }

You can find the source here. What this algorithm does is say "If my x coordinate is greater than the other rectangle's x coordinate and less than its x coordinate + its width, then we overlap on the X axis." The same is done for the Y axis. If the rectangles overlap on both axis, then we consider it to be a collision.

The tricky part is figuring out what to do once the collision has been detected. If we detect it by seeing the overlap, that means Bob (our actor) has embedded himself in the wall (which clearly shouldn't happen). We can solve this by doing one of two things: A) We push him back out of the wall before we render, or B) Before we move him we simulate his movement to see if he would collide. The code you reference opts for the latter.

The algorithm has been further optimized to only check for collisions near Bob, instead of checking to see if he has collided with every tile in the game (which gets to be very expensive, especially when you have multiple things moving around besides Bob which require collision checks).

Hopefully that makes sense.

\$\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.