Slick2D 与 tilemap 的碰撞

Slick2D collision with tilemap

我知道 Slick2D 已被废弃,但我觉得用这个库键入代码很舒服。

也许你对 Slick2d 也有同样的看法,碰撞。现在,我有一个我无法解决的问题,我已经为这个问题困扰了 2 周。在我的游戏中,有一个 TileMap,我在其中找到属于 "solid" 层的所有元素,并且我在相同位置绘制矩形以处理物理。问题是我的角色(有一定数量的动画)没有检测到属于我的 tilemap 实体层的矩形。

如果我使用 for 循环,角色不会检测到矩形。但是,如果我通过 ifs 语句检查所有矩形,则碰撞有效。

有人知道为什么会这样吗?

抱歉我的英语不好>.<

我们将不胜感激。

谢谢!

编辑:这是关于我的碰撞的代码。

关卡 class 包含瓦片地图:

public class Level extends TiledMap{

private int tileId;
private int layerIndex;
private boolean solids[][];
private Shape rects[][];

public Level(String path) throws SlickException {
    super(path);
    solids = new boolean [super.getWidth()][super.getHeight()];
    rects = new Rectangle[super.getWidth()][super.getHeight()];
    tileId=0;
    layerIndex=0;
}

public int getTileId() {
    return tileId;
}

public int getLayerIndex() {
    return layerIndex;
}

public boolean[][] getSolids() {
    return solids;
}

public Shape[][] getRects() {
    return rects;
}
public Shape getSingleRect(int i, int j){
    return rects[i][j];
}

public void setTileId(int tileId) {
    this.tileId = tileId;
}

public void setLayerIndex(String layerName) {
    this.layerIndex = super.getLayerIndex(layerName);
}

public void setSolid(int i, int j, boolean solid) {
    this.solids[j][i] = solid;
}

public void setRect(int i, int j, Shape rect) {
    this.rects[j][i] = rect;
}

//other methods
public void printSolidMatrix(){
    System.out.println("SOLID MATRIX");
    for(int i=0;i<super.getWidth();i++){
        for(int j=0;j<super.getHeight();j++){
            System.out.print(solids[j][i]+" ");
        }
        System.out.println();
    }
}

public void drawDebugRects(Graphics g){
    layerIndex = this.getLayerIndex();
    tileId = 0;
    for(int i=0;i<this.getWidth();i++){
        for(int j=0;j<this.getHeight();j++){
            tileId = this.getTileId(j, i, layerIndex);
            g.draw(rects[j][i]);
        }
    }
}
public boolean collidesWith(Shape s){
    for(int i=0;i<this.getWidth();i++){
      for(int j=0;j<this.getHeight;j++){
          if(s.intersects(rects[j][i]) && solids[j][i]){
          }
      }
    }
    return false;
}

}

我的播放器class具有关于物理的属性:

public class Player{

private Level map;
private float x;
private float y;
private boolean falling;

private Shape bounds;

public Player(Level map) throws SlickException{ 

    falling = true;
    x=0;
    y=500;
    this.map = map;
    this.setBounds(this.x, this.y, this.x*32, this.y*32);
}
public float getX() {
    return x;
}
public void increaseX(float x) {
    this.x += x;
}
public float getY() {
    return y;
}
public void increaseY(float y) {
    this.y += y;
}
public Shape getBounds() {
    return bounds;
}
public void setBounds(float x, float y, float width, float height) {
    bounds = new Rectangle(x, y, this.currentAnimation.getWidth(), this.currentAnimation.getHeight());
}
public boolean isFalling() {
    return falling;
}
public void setFalling(boolean falling) {
    this.falling = falling;
}

public void render(GameContainer gc, Graphics g) throws SlickException {
    this.getCurrentAnimation().draw(this.getX(), this.getY());
    this.setBounds(this.getX(), this.getY(), this.getCurrentAnimation().getWidth(),this.getCurrentAnimation().getHeight());
    g.draw(this.getBounds());
}
public void update(GameContainer gc, int delta) throws SlickException {
    this.getCurrentAnimation().update(delta);
    //character movement
            if(gc.getInput().isKeyDown(Input.KEY_D)){
                this.setRight(true);
                this.setCurrentAnimation(this.getWalkAnimation());
                this.increaseX(2.5f);
            }

            else if(gc.getInput().isKeyDown(Input.KEY_A)){
                this.setRight(false);
                this.setCurrentAnimation(this.getWalkAnimationReverse());

                if(this.getX()<0){

                }else{
                    this.increaseX(-2.5f);
                }
            }
            else{
                if(!this.isRight()){
                    this.setCurrentAnimation(this.getStandAnimationReverse());
                }else{
                    this.setCurrentAnimation(this.getDefaultAnimation());
                }
            }       
}

}

我目前的工作水平:

public class IntroStage extends BasicGameState{


Level map;
Player p;


@Override
public void init(GameContainer gc, StateBasedGame sbg) throws SlickException {
    initMap();
    p = new Player(map); 
    //map.printSolidMatrix();
}

@Override
public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException {
    map.render(0, 0);
    map.drawDebugRects(g);
    p.render(gc, g);
}

@Override
public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException {
    p.update(gc, delta);

    //this if make character fall while he doesnt collides
    if(map.collidesWith(p.getBounds())){
       p.increaseY(delta);
    }
    else{
       p.increaseY(0);
    }
}

@Override
public int getID() {
    return 1;
}


public void initMap() throws SlickException{
    map = new Level("res/tiles/test.tmx");
    map.setLayerIndex("suelo");
    int id=0;
    int x=0;
    int y=0;
    for(int i=0; i<map.getWidth();i++){
        for(int j=0;j<map.getHeight();j++){
            id = map.getTileId(j, i, map.getLayerIndex());
            x=j*32;
            y=i*32;
            map.setRect(i, j, new Rectangle(x, y, map.getTileWidth(), map.getTileHeight())); 
            if(id!=0){
                map.setSolid(i, j, true);
            }
            else{
                map.setSolid(i, j, false);
            }
        }
    }
}

}

注意:Slick2D 中的 getTileId 方法效果不佳,这就是我使用 matrix[j][i] 而不是 matrix[i][j][=13 的原因=]

所以网上有很多教程解释了如何做到这一点:

我可以推荐这些以更好地了解您可能做错了什么:

Slick2d | Entity collision detection

https://gamedev.stackexchange.com/questions/59308/how-do-i-detect-and-handle-collisions-using-a-tile-property-with-slick2d


我强烈建议给你的玩家一个碰撞箱。例如一个 32*32 的矩形,这对于 easy & precise 碰撞检测是必不可少的,因为你可以使用 shape.intersects(形状 s) 方法。

我检查了您的代码,据我了解缺少的是播放器端的碰撞检测。所以现在您正在确​​定哪些图块是 "blocked"。从您的方法中,每个块块都是一个形状,其 x,y 存储在数组中。

你需要在玩家端做的是在移动动作之后检查你的玩家想要移动的方向是否被阻挡。

没有 Player 碰撞箱的方法可能会表现不准确,这取决于您的速度。这在每个移动命令 1 个方块的速度下效果最佳。 例如

if(gc.getInput().isKeyDown(Input.KEY_D)){
   if(Level.solids[Player.x+Player.xv][Player.y] == false){ // Checking whether the tile to the right of the Player is returning false or true
   // ...Do your movement / Animation stuff.
   }

}

在我看来,如果你也这样做并通过形状检查碰撞会更好。

if(gc.getInput().isKeyDown(Input.KEY_D)){
   for(Shape s : Level.shapes){
   if(!Player.hitbox.intersects(s)){
   // ...Do your movement / Animation stuff.
   }

请注意,您可能无法一一使用它,因为它的行为不准确,您需要根据自己的需要对其进行调整。但它应该重新考虑您的游戏设计并给您提示您的问题可能出在哪里。

希望对您有所帮助。