简体   繁体   English

与tilemap的Slick2D碰撞

[英]Slick2D collision with tilemap

I know that Slick2D is abandoned but I feel comfortable type code with this library. 我知道Slick2D被放弃了,但是我对此库的类型代码感到满意。

Maybe you've seen the same thing about Slick2d, collisions. 也许您已经对Slick2d发生了相同的碰撞。 Now, I have an issue that I cannot solve, and I am with this problem for 2 weeks. 现在,我有一个无法解决的问题,并且这个问题持续了两个星期。 In my game, there is a TileMap, where I found all of elements that belongs to "solid" Layer and I draw rectangles at the same position to work with physics. 在我的游戏中,有一个TileMap,在其中找到了属于“实体”图层的所有元素,并在同一位置绘制矩形以使用物理。 The problem is that my character (is an amount of animations) doesnt detect the rectangles that belongs to the solid layer of my tilemap. 问题是我的角色(有一定数量的动画)没有检测到属于我的tilemap实体层的矩形。

If I use a for loop, the character doesnt detect the rectangles. 如果我使用for循环,则该字符不会检测到矩形。 But if I check through ifs statements all of rects, the collision works. 但是,如果我检查所有rect的ifs语句,则冲突有效。

Does anyone know why is this happenning? 有谁知道为什么会这样?

Sorry about my English >.< 对不起,我的英语>。<

Any help will be apreciated. 任何帮助将不胜感激。

Thanks! 谢谢!

Edit: Here is the code about my collision. 编辑:这是关于我的碰撞的代码。

Level class which contains the tilemap: 包含tilemap的Level类:

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;
}

} }

My player class with the attributes about physics: 我的播放器类具有有关物理的属性:

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());
                }
            }       
}

} }

The current level on I am working: 我正在使用的当前级别:

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);
            }
        }
    }
}

} }

NOTE : The method getTileId from Slick2D doesnt work well, that's why I am using matrix[j][i] instead of matrix[i][j] 注意 :Slick2D中的方法getTileId不能很好地工作,这就是为什么我使用matrix [j] [i]而不是matrix [i] [j]的原因

So there are a lot of tutorials on the Internet which explains how to do this: 因此,Internet上有很多教程介绍了如何执行此操作:

I can recommened These to get a good understanding of what you might be doing wrong: 我可以推荐这些,以使您更好地了解自己可能做错了什么:

Slick2d | Slick2d | Entity collision detection 实体碰撞检测

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


I strongly recommend to give your Player a hitbox. 我强烈建议您为播放器添加一个点击框。 For Example a 32*32 rectangle, this is essential for easy & precise collision detection since you can make use of the shape.intersects(Shape s) method. 例如,一个32 * 32矩形,这对于轻松 准确地进行碰撞检测至关重要,因为您可以使用shape.intersects(Shape s)方法。

I checked out your code and what is missing from my understanding what is missing is the collision detection on the Player side. 我检查了您的代码,从我的理解中了解到缺少的是Player一侧的碰撞检测。 So right now you are determining which tiles are "blocked". 因此,现在您要确定哪些图块被“阻止”了。 From your Approach every blocked tile is a Shape with ax,y stored in a Array. 从您的方法中,每个阻塞的图块都是一个形状为ax,y的形状,存储在数组中。

What you Need to do on playerside is checking after the movement Action if the direction where your Player wants to move is blocked or not. 您需要在播放器端执行的操作是在执行动作后检查播放器要移动的方向是否被阻塞。

Approach without a Player hitbox, might behave unprecisily though and depends on your velocity. 没有Player击中框的方法可能会表现得异常精确,并取决于您的速度。 This should work best with a velocity of 1 tile per movement command. 每个移动命令的速度为1个图块时,该效果最好。 EG 例如

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.
   }

}

In my opinion it would be better if you do the same with checking for collision by shapes. 在我看来,如果对形状冲突进行检查,效果会更好。

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

Note that you probably wont be able to use this one by one since it will behave imprecisely, you'll Need to tweak it to your demands. 请注意,您可能无法一一使用它,因为它的行为可能不精确,您需要根据自己的需求进行调整。 But its supposed to rethink your game design and give you a hint where ur Problem might be. 但是它应该重新考虑您的游戏设计,并提示您问题可能出在哪里。

Hope this helps you. 希望这对您有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM