简体   繁体   English

Java:2D世界碰撞检测代码错误

[英]Java: 2D world collision detection code bug

this is the second game that I'm having issues with in the same area... the first one I don't even know how I fixed it exactly. 这是我在同一地区遇到的第二个游戏……第一个我什至不知道如何准确地解决它。 The coordinate system was also in doubles. 坐标系也加倍。

This is the "update" code for the physics class that will be inherited by all the objects in the world (players, enemies, items). 这是物理类的“更新”代码,将被世界上所有对象(玩家,敌人,物品)继承。 All these objects will have to be able to obey collisions with the world, so... when they have a xSpeed or ySpeed this part of the code will run to apply and "snap" the object into the correct space if it hits a solid (dubbed state 2) world tile. 所有这些对象都必须能够服从与世界的碰撞,因此...当它们具有xSpeed或ySpeed时,这部分代码将运行以应用并将对象“击中”到正确的空间(如果碰到固体) (称为状态2)世界图块。 Each world tile is 20x20 pixels. 每个世界图块均为20x20像素。

Problem: It works perfectly fine except... 问题:效果很好,除了...

if you snap to the right tile, then you cannot move up or down. 如果捕捉到正确的图块,则无法向上或向下移动。 (though you can move left, and then move up or down) (尽管您可以向左移动,然后向上或向下移动)

if you snap to the bottom tile, then you cannot move left or right. 如果捕捉到底部图块,则无法向左或向右移动。 (though you can move up and then move left or right) (尽管您可以向上移动然后向左或向右移动)

    if(xSpeed<0){
        try{
            int dest = hitbox.x + (int)(xSpeed/20*tick);
            if(Ids.tiles[world[dest/20][hitbox.y/20]].getState() == 2 || Ids.tiles[world[dest/20][(hitbox.y+hitbox.width)/20]].getState() == 2){
                hitbox.x = (int)Math.ceil(dest/20.)*20;
                xSpeed = 0;
            }else{
                hitbox.x += (int)(xSpeed/20*tick);
            }
        }catch(Exception e){
            hitbox.x += (int)(xSpeed/20*tick);
        }
    }else if(xSpeed>0){
        try{
            int dest = hitbox.x+hitbox.width+(int)(xSpeed/20*tick);
            if(Ids.tiles[world[dest/20][hitbox.y/20]].getState() == 2 || Ids.tiles[world[dest/20][(hitbox.y + hitbox.width)/20]].getState() == 2){
                hitbox.x = dest/20*20 - hitbox.width;
                xSpeed = 0;
            }else{
                hitbox.x += (int)(xSpeed/20*tick);
            }
        }catch(Exception e){
            hitbox.x += (int)(xSpeed/20*tick);
        }
    }

    if(ySpeed<0){
        try{
            int dest =  hitbox.y + (int)(ySpeed/20*tick);
            if(Ids.tiles[world[hitbox.x/20][dest/20]].getState() == 2 || Ids.tiles[world[(hitbox.x + hitbox.width)/20][dest/20]].getState() == 2){
                hitbox.y = (int)Math.ceil(dest/20.)*20;
                ySpeed = 0;
            }else{
                hitbox.y +=  (int)(ySpeed/20*tick);;
            }
        }catch(Exception e){
            hitbox.y +=  (int)(ySpeed/20*tick);;
        }
    }else if(ySpeed>0){
        try{
            int dest = hitbox.y + hitbox.height +  (int)(ySpeed/20*tick);
            if(Ids.tiles[world[hitbox.x/20][dest/20]].getState() == 2 || Ids.tiles[world[(hitbox.x + hitbox.width)/20][dest/20]].getState() == 2){
                hitbox.y = dest/20*20 - hitbox.height;
                ySpeed = 0;
            }else{
                hitbox.y +=  (int)(ySpeed/20*tick);;
            }
        }catch(Exception e){
            hitbox.y +=  (int)(ySpeed/20*tick);;
        }
    }

Consider what happens on a right-edge (moving rightward) collision. 考虑一下在右边缘(向右移动)碰撞时会发生什么。 This condition passes: 此条件通过:

Ids.tiles[world[dest/20][hitbox.y/20]].getState() == 2

Suppose hitbox.width is 5. Then this will return true as soon as hitbox.x is 15. But you then reset hitbox.x to dest/20*20 - hitbox.width , which works out to be exactly where it already is. 假设hitbox.width为5,则一旦hitbox.x为15, hitbox.x立即返回true。但是然后,您将hitbox.x重置为dest/20*20 - hitbox.width ,它可以精确dest/20*20 - hitbox.width所在位置。 Then, in the vertical direction, if the object moves then its rightmost edge is already colliding with tiles, so it can't move. 然后,在垂直方向上,如果对象移动,则其最右边已经与图块发生碰撞,因此它无法移动。

To fix this, subtract 1 pixel from the hitbox size when using it to look up grid positions — before the division, of course. 要解决此问题,请在使用命中框大小查找网格位置时从命中框大小中减去1个像素-当然要在划分之前。

If you were working in floating-point coordinates, then you would use Math.ceil((hitbox.x + hitbox.width)/20.0) - 1 to produce a similar effect without having an arbitrary epsilon. 如果使用浮点坐标,则可以使用Math.ceil((hitbox.x + hitbox.width)/20.0) - 1产生类似的效果,而不会产生任意的epsilon。

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

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