проблема с угловым столкновением на 2D платформере - PullRequest
0 голосов
/ 09 октября 2019

Я читал урок, все было хорошо, пока я не решил изменить параметры столкновения персонажа. с 20 * 20 до 81 * 64 после этого персонаж начинает подпрыгивать. Как я могу изменить параметры, чтобы он работал нормально?

первая часть кода представляет собой «класс MapObject»

// tile stuff
protected TileMap tileMap;
protected int tileSize;
protected double xmap;
protected double ymap;

// position and vector
protected double x;
protected double y;
protected double dx;
protected double dy;

// dimensions
protected int width;
protected int height;

// collision box
protected int cwidth;
protected int cheight;

// collision
protected int currRow;
protected int currCol;
protected double xdest;
protected double ydest;
protected double xtemp;
protected double ytemp;
protected boolean topLeft;
protected boolean topRight;
protected boolean bottomLeft;
protected boolean bottomRight;

// animation
protected Animation animation;
protected int currentAction;
protected int previousAction;
protected boolean facingRight;

// movement
protected boolean left;
protected boolean right;
protected boolean up;
protected boolean down;
protected boolean jumping;
protected boolean falling;

// movement attributes
protected double moveSpeed;
protected double maxSpeed;
protected double stopSpeed;
protected double fallSpeed;
protected double maxFallSpeed;
protected double jumpStart;
protected double stopJumpSpeed;

// constructor
public MapObject(TileMap tm) {
    tileMap = tm;
    tileSize = tm.getTileSize(); 
}

public boolean intersects(MapObject o) {
    Rectangle r1 = getRectangle();
    Rectangle r2 = o.getRectangle();
    return r1.intersects(r2);
}

public Rectangle getRectangle() {
    return new Rectangle(
            (int)x - cwidth,
            (int)y - cheight,
            cwidth,
            cheight
    );
}

public void calculateCorners(double x, double y) {

    int leftTile = (int)(x - cwidth / 2) / tileSize;
    int rightTile = (int)(x + cwidth / 2 - 1) / tileSize;
    int topTile = (int)(y - cheight / 2) / tileSize;
    int bottomTile = (int)(y + cheight / 2 - 1) / tileSize;

    int tl = tileMap.getType(topTile, leftTile);
    int tr = tileMap.getType(topTile, rightTile);
    int bl = tileMap.getType(bottomTile, leftTile);
    int br = tileMap.getType(bottomTile, rightTile);

    topLeft = tl == Tile.BLOCKED;
    topRight = tr == Tile.BLOCKED;
    bottomLeft = bl == Tile.BLOCKED;
    bottomRight = br == Tile.BLOCKED;

}

public void checkTileMapCollision() {

    currCol = (int)x / tileSize;
    currRow = (int)y / tileSize;

    xdest = x + dx;
    ydest = y + dy;

    xtemp = x;
    ytemp = y;

    calculateCorners(x, ydest);
    if(dy < 0) {
        if(topLeft || topRight) {
            dy = 0;
            ytemp = currRow * tileSize + cheight / 2;
        }
        else {
            ytemp += dy;
        }
    }
    if(dy > 0) {
        if(bottomLeft || bottomRight) {
            dy = 0;
            falling = false;
            ytemp = (currRow-1) * tileSize - cheight / 2;
        }
        else {
            ytemp += dy;
        }
    }

    calculateCorners(xdest, y);
    if(dx < 0) {
        if(topLeft || bottomLeft) {
            dx = 0;
            xtemp = currCol * tileSize + cwidth / 2;
        }
        else {
            xtemp += dx;
        }
    }
    if(dx > 0) {
        if(topRight || bottomRight) {
            dx = 0;
            xtemp = (currCol + 1) * tileSize - cwidth / 2;
        }
        else {
            xtemp += dx;
        }
    }

    if(!falling) {
        calculateCorners(x, ydest + 1);
        if(!bottomLeft && !bottomRight) {
            falling = true;
        }
    }

}

public int getx() { return (int)x; }
public int gety() { return (int)y; }
public int getWidth() { return width; }
public int getHeight() { return height; }
public int getCWidth() { return cwidth; }
public int getCHeight() { return cheight; }

public void setPosition(double x, double y) {
    this.x = x;
    this.y = y;
}
public void setVector(double dx, double dy) {
    this.dx = dx;
    this.dy = dy;
}

public void setMapPosition() {
    xmap = tileMap.getx();
    ymap = tileMap.gety();
}

public void setLeft(boolean b) { left = b; }
public void setRight(boolean b) { right = b; }
public void setUp(boolean b) { up = b; }
public void setDown(boolean b) { down = b; }
public void setJumping(boolean b) { jumping = b; }

public boolean notOnScreen() {
    return x + xmap + width < 0 ||
        x + xmap - width > GamePanel.WIDTH ||
        y + ymap + height < 0 ||
        y + ymap - height > GamePanel.HEIGHT;
}

public void draw(java.awt.Graphics2D g) {
    if(facingRight) {
        g.drawImage(
            animation.getImage(),
            (int)(x + xmap - width / 2),
            (int)(y + ymap - height / 2),
            null
        );
        //debug
        g.setColor(Color.white);
        g.drawRect((int)(x + xmap - width / 2),(int)(y + ymap - height / 2),width,height );
    }
    else {
        g.drawImage(
            animation.getImage(),
            (int)(x + xmap - width / 2 + width),
            (int)(y + ymap - height / 2),
            -width,
            height,
            null
        );
        //debug
        g.setColor(Color.white);
        g.drawRect((int)(x + xmap - width / 2 + width),(int)(y + ymap - height / 2),-width,height );

    }
}

вторая часть кода представляет собой «класс игрока»

// player stuff
private int health;
private int maxHealth;
private int fire;
private int maxFire;
private boolean dead;
private boolean flinching;
private long flinchTimer;

// fireball
private boolean firing;
private int fireCost;
private int fireBallDamage;
private ArrayList<FireBall> fireBalls;

// scratch
private boolean scratching;
private int scratchDamage;
private int scratchRange;

// gliding
private boolean gliding;

// animations
private ArrayList<BufferedImage[]> sprites;
private final int[] numFrames = {
    2, 8, 1, 2, 4, 2, 5
};

// animation actions
private static final int IDLE = 0;
private static final int WALKING = 1;
private static final int JUMPING = 2;
private static final int FALLING = 3;
private static final int GLIDING = 4;
private static final int FIREBALL = 5;
private static final int SCRATCHING = 6;

public Player(TileMap tm) {

    super(tm);

    width = 30;
    height = 30;
    cwidth = 81; //works with 20
    cheight = 64; //works until 60

    moveSpeed = 0.3;
    maxSpeed = 1.6;
    stopSpeed = 0.4;
    fallSpeed = 0.15;
    maxFallSpeed = 4.0;
    jumpStart = -4.8;
    stopJumpSpeed = 0.3;

    facingRight = true;

    health = maxHealth = 5;
    fire = maxFire = 2500;

    fireCost = 200;
    fireBallDamage = 5;
    fireBalls = new ArrayList<FireBall>();

    scratchDamage = 8;
    scratchRange = 40;

    // load sprites
    try {

        BufferedImage spritesheet = ImageIO.read(
            getClass().getResourceAsStream(
                "/Sprites/Player/playersprites.gif"
            )
        );

        sprites = new ArrayList<BufferedImage[]>();
        for(int i = 0; i < 7; i++) {

            BufferedImage[] bi =
                new BufferedImage[numFrames[i]];

            for(int j = 0; j < numFrames[i]; j++) {

                if(i != SCRATCHING) {
                    bi[j] = spritesheet.getSubimage(
                            j * width,
                            i * height,
                            width,
                            height
                    );
                }
                else {
                    bi[j] = spritesheet.getSubimage(
                            j * width * 2,
                            i * height,
                            width * 2,
                            height
                    );
                }

            }

            sprites.add(bi);

        }

    }
    catch(Exception e) {
        e.printStackTrace();
    }

    animation = new Animation();
    currentAction = IDLE;
    animation.setFrames(sprites.get(IDLE));
    animation.setDelay(400);

}

public int getHealth() { return health; }
public int getMaxHealth() { return maxHealth; }
public int getFire() { return fire; }
public int getMaxFire() { return maxFire; }

public void setFiring() { 
    firing = true;
}
public void setScratching() {
    scratching = true;
}
public void setGliding(boolean b) { 
    gliding = b;
}

public void checkAttack(ArrayList<Enemy> enemies) {

    // loop through enemies
    for(int i = 0; i < enemies.size(); i++) {

        Enemy e = enemies.get(i);

        // scratch attack
        if(scratching) {
            if(facingRight) {
                if(
                    e.getx() > x &&
                    e.getx() < x + scratchRange && 
                    e.gety() > y - height / 2 &&
                    e.gety() < y + height / 2
                ) {
                    e.hit(scratchDamage);
                }
            }
            else {
                if(
                    e.getx() < x &&
                    e.getx() > x - scratchRange &&
                    e.gety() > y - height / 2 &&
                    e.gety() < y + height / 2
                ) {
                    e.hit(scratchDamage);
                }
            }
        }

        // fireballs
        for(int j = 0; j < fireBalls.size(); j++) {
            if(fireBalls.get(j).intersects(e)) {
                e.hit(fireBallDamage);
                fireBalls.get(j).setHit();
                break;
            }
        }

        // check enemy collision
        if(intersects(e)) {
            hit(e.getDamage());
        }

    }

}

public void hit(int damage) {
    if(flinching) return;
    health -= damage;
    if(health < 0) health = 0;
    if(health == 0) dead = true;
    flinching = true;
    flinchTimer = System.nanoTime();
}

private void getNextPosition() {

    // movement
    if(left) {
        dx -= moveSpeed;
        if(dx < -maxSpeed) {
            dx = -maxSpeed;
        }
    }
    else if(right) {
        dx += moveSpeed;
        if(dx > maxSpeed) {
            dx = maxSpeed;
        }
    }
    else {
        if(dx > 0) {
            dx -= stopSpeed;
            if(dx < 0) {
                dx = 0;
            }
        }
        else if(dx < 0) {
            dx += stopSpeed;
            if(dx > 0) {
                dx = 0;
            }
        }
    }

    // cannot move while attacking, except in air
    if(
    (currentAction == SCRATCHING || currentAction == FIREBALL) &&
    !(jumping || falling)) {
        dx = 0;
    }

    // jumping
    if(jumping && !falling) {
        dy = jumpStart;
        falling = true; 
    }

    // falling
    if(falling) {

        if(dy > 0 && gliding) dy += fallSpeed * 0.1;
        else dy += fallSpeed;

        if(dy > 0) jumping = false;
        if(dy < 0 && !jumping) dy += stopJumpSpeed;

        if(dy > maxFallSpeed) dy = maxFallSpeed;

    }

}

public void update() {

    // update position
    getNextPosition();
    checkTileMapCollision();
    setPosition(xtemp, ytemp);

    // check attack has stopped
    if(currentAction == SCRATCHING) {
        if(animation.hasPlayedOnce()) scratching = false;
    }
    if(currentAction == FIREBALL) {
        if(animation.hasPlayedOnce()) firing = false;
    }

    // fireball attack
    fire += 1;
    if(fire > maxFire) fire = maxFire;
    if(firing && currentAction != FIREBALL) {
        if(fire > fireCost) {
            fire -= fireCost;
            FireBall fb = new FireBall(tileMap, facingRight);
            fb.setPosition(x, y);
            fireBalls.add(fb);
        }
    }

    // update fireballs
    for(int i = 0; i < fireBalls.size(); i++) {
        fireBalls.get(i).update();
        if(fireBalls.get(i).shouldRemove()) {
            fireBalls.remove(i);
            i--;
        }
    }

    // check done flinching
    if(flinching) {
        long elapsed =
            (System.nanoTime() - flinchTimer) / 1000000;
        if(elapsed > 1000) {
            flinching = false;
        }
    }

    // set animation
    if(scratching) {
        if(currentAction != SCRATCHING) {
            currentAction = SCRATCHING;
            animation.setFrames(sprites.get(SCRATCHING));
            animation.setDelay(50);
            width = 60;
        }
    }
    else if(firing) {
        if(currentAction != FIREBALL) {
            currentAction = FIREBALL;
            animation.setFrames(sprites.get(FIREBALL));
            animation.setDelay(100);
            width = 30;
        }
    }
    else if(dy > 0) {
        if(gliding) {
            if(currentAction != GLIDING) {
                currentAction = GLIDING;
                animation.setFrames(sprites.get(GLIDING));
                animation.setDelay(100);
                width = 30;
            }
        }
        else if(currentAction != FALLING) {
            currentAction = FALLING;
            animation.setFrames(sprites.get(FALLING));
            animation.setDelay(100);
            width = 30;
        }
    }
    else if(dy < 0) {
        if(currentAction != JUMPING) {
            currentAction = JUMPING;
            animation.setFrames(sprites.get(JUMPING));
            animation.setDelay(-1);
            width = 30;
        }
    }
    else if(left || right) {
        if(currentAction != WALKING) {
            currentAction = WALKING;
            animation.setFrames(sprites.get(WALKING));
            animation.setDelay(40);
            width = 30;
        }
    }
    else {
        if(currentAction != IDLE) {
            currentAction = IDLE;
            animation.setFrames(sprites.get(IDLE));
            animation.setDelay(400);
            width = 30;
        }
    }

    animation.update();

    // set direction
    if(currentAction != SCRATCHING && currentAction != FIREBALL) {
        if(right) facingRight = true;
        if(left) facingRight = false;
    }

}

public void draw(Graphics2D g) {

    setMapPosition();

    // draw fireballs
    for(int i = 0; i < fireBalls.size(); i++) {
        fireBalls.get(i).draw(g);
    }

    // draw player
    if(flinching) {
        long elapsed =
            (System.nanoTime() - flinchTimer) / 1000000;
        if(elapsed / 100 % 2 == 0) {
            return;

        }
    }

    super.draw(g);


}

}

...