Question

I have a set of methods in my platformer in progress to detect and resolve collisions between entities and the tilemap, but they are doing a bad job of it.

The bottom method is the one being called, like this:

player.velocity = player.velocity.add(getFinalCollisionVector());

where player.velocity is a Vec2D.

private List<Rectangle2D> getCollidingTiles(){
    List<Rectangle2D> collidingTiles = new ArrayList<Rectangle2D>();
    for(int x = (int) (this.getX()/Tile.SIZE); x <= (int) (this.getX()/Tile.SIZE) + this.getRect2D().getWidth()/Tile.SIZE; x++){
        for(int y = (int) (this.getX()/Tile.SIZE); y <= (int) (this.getX()/Tile.SIZE) +  this.getRect2D().getHeight()/Tile.SIZE; y++){

            if(map.getTileAt(x, y).getAttribute(Attribute.SOLID))
                if(map.getCollisionBoxAt(x,y).isColliding(this.collisionBox))
                    collidingTiles.add(new Rectangle2D.Double(x, y, Tile.SIZE, Tile.SIZE));
        }
    }       

    return collidingTiles;
}
private List<Vec2D> getAllTileCollisionVectors(){
    List<Rectangle2D> collidingTiles = getCollidingTiles();
    List<Vec2D> collisionVectors = new ArrayList<Vec2D>();
    for(Rectangle2D rec : collidingTiles){
        collisionVectors.add(getCorrectionVector(rec));
    }
    return collisionVectors;
}
private Vec2D getCorrectionVector(Rectangle2D target)
{
    Vec2D ret = new Vec2D();

    double x1 = (this.getX() + this.getSize().x) - target.getX();
    double x2 = this.getX() - (target.getX() + target.getWidth());
    double y1 = (this.getY() + this.getSize().y) - target.getY();
    double y2 = this.getY() - (target.getY() + target.getHeight());
    // calculate displacement along X-axis
    if (x1 < x2)
    {
        ret.x = x1;
    }
    else if (x1 > x2)
    {
        ret.x = x2;
    }
    // calculate displacement along Y-axis
    if (y1 < y2)
    {
        ret.y = y1;
    }
    else if (y1 > y2)
    {
        ret.y = y2;
    }
    return ret;
}
protected Vec2D getFinalCollisionVector(){
    List<Vec2D> collisionVectors = getAllTileCollisionVectors();
    if(collisionVectors.size() < 1)
        return new Vec2D(0,0);

    Vec2D finalVector = new Vec2D();
    for(Vec2D vec : collisionVectors){
        finalVector = finalVector.add(vec);
    }       
    return finalVector;
}

What am I doing wrong in my code? This is the behavior that the player shows, where he falls (due to gravity) to that point, and then he freezes. The character is stuck

Was it helpful?

Solution

OP here: Since there are no other answers, I've posted my own.

I've abandonded the old implementation,started from the ground up, and it works now. This is the new implementation:

    public Corners getCornersAreSolid(double x, double y) {
    int leftTile = (int)(x / Tile.SIZE);
    int rightTile = (int)((x + moveData.collisionBox.getWidth()) / Tile.SIZE);
    int topTile = (int)(y / Tile.SIZE);
    int bottomTile = (int)((y + moveData.collisionBox.getHeight()) / Tile.SIZE);

    boolean topLeft = hasAttribute(map, Attribute.SOLID, topTile, leftTile);
    boolean topRight = hasAttribute(map, Attribute.SOLID, topTile, rightTile);
    boolean bottomLeft = hasAttribute(map, Attribute.SOLID, bottomTile, leftTile);
    boolean bottomRight = hasAttribute(map, Attribute.SOLID, bottomTile, rightTile);

    Corners solidCorners = new Corners();
    solidCorners.topLeft = topLeft;
    solidCorners.topRight = topRight;
    solidCorners.bottomRight = bottomRight;
    solidCorners.bottomLeft = bottomLeft;
    return solidCorners;
}
private boolean hasAttribute(GameMap map, Attribute attribute, int tileY, int tileX) {
      boolean result = false;

      if (tileX >= 0 && tileX < map.getWidthInTiles() && tileY >= 0 && tileY < map.getHeightInTiles()) {
        result = map.getTileAt(tileX, tileY).getAttribute(attribute);
      }
      return result;
    }
public Vec2D getNextPosition() {

    int currCol = (int) (getX() / Tile.SIZE);
    int currRow = (int) (getY() / Tile.SIZE);

    double destX = getX() + moveData.velocity.x;
    double destY = getY() + moveData.velocity.y;

    double tempX = getX();
    double tempY = getY();

    Corners solidCorners = getCornersAreSolid(getX(), destY);
    boolean topLeft = solidCorners.topLeft;
    boolean topRight = solidCorners.topRight;
    boolean bottomLeft = solidCorners.bottomLeft;
    boolean bottomRight = solidCorners.bottomRight;

    this.framesSinceLastCollision += 1;
    if(moveData.velocity.y < 0) {
        if(topLeft || topRight) {
            moveData.velocity.y = 0;
            tempY = currRow * Tile.SIZE;
            this.framesSinceLastCollision = 0;
        }
        else {
            tempY += moveData.velocity.y;
        }
    }
    else if(moveData.velocity.y > 0) {
        if(bottomLeft || bottomRight) {
            moveData.velocity.y = 0;
            tempY = (currRow + 1) * Tile.SIZE - moveData.collisionBox.getHeight() % Tile.SIZE - 1 ;
            this.framesSinceLastCollision = 0;
        }
        else {
            tempY += moveData.velocity.y;
        }
    }

    solidCorners = getCornersAreSolid(destX, getY());
    topLeft = solidCorners.topLeft;
    topRight = solidCorners.topRight;
    bottomLeft = solidCorners.bottomLeft;
    bottomRight = solidCorners.bottomRight;
    if(moveData.velocity.x < 0) {
        if(topLeft || bottomLeft) {
            moveData.velocity.x = 0;
            tempX = currCol * Tile.SIZE;
            this.framesSinceLastCollision = 0;
        }
        else {
            tempX += moveData.velocity.x;
        }
    }
    if(moveData.velocity.x > 0) {
        if(topRight || bottomRight) {
            moveData.velocity.x = 0;
            tempX = (currCol + 1) * Tile.SIZE - moveData.collisionBox.getWidth() % Tile.SIZE -1 ;
            this.framesSinceLastCollision = 0;
        }
        else {
            tempX += moveData.velocity.x;
        }
    }
    return new Vec2D(tempX, tempY);
}
private static class Corners{
    public boolean topLeft, topRight;
    public boolean bottomLeft, bottomRight;
    public Corners(){
        topLeft = false;
        topRight = false;
        bottomLeft = false;
        bottomRight = false;
    }       
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top