Domanda

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

È stato utile?

Soluzione

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;
    }       
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top