简体   繁体   English

java swing - 如何确定两个矩形之间碰撞的一面

[英]java swing - how to determine the side of a collision between two rectangles

I'm building a top-down 2D scroller using java swing with very similar gameplay to that of the classic game Bomberman, where the player can move the character in all 4 cardinal directions. 我正在使用java swing构建一个自上而下的2D滚动条,其游戏玩法与经典游戏Bomberman非常相似,玩家可以在所有4个主要方向上移动角色。

All the game objects have instance variables containing the (x,y) coordinates of where they are to be rendered on the JPanel, they also have instance variables for the previous (x,y) coordinate where they were rendered in the last frame. 所有游戏对象都有实例变量,包含它们在JPanel上渲染的位置的(x,y)坐标,它们还有前一个(x,y)坐标的实例变量,它们在最后一帧中被渲染。 My collision detection algorithm essentially checks to see if the player object intersects one of the walls present in the grid every time we refresh the screen - This can be seen in the bit of code below: 我的碰撞检测算法基本上检查每次刷新屏幕时玩家对象是否与网格中存在的一个墙相交 - 这可以在下面的代码中看到:

if (playerRectangle.intersects(wallRectangle)) {
  player.restorePreviousPosition();
}

The restorePreviousPosition() method sets the (x,y) coordinates of the player to what they were before the collision occurred. restorePreviousPosition()方法将播放器的(x,y)坐标设置为碰撞发生前的坐标。 This methods works fine, it prevents the player from going through objects. 这种方法工作正常,它可以防止玩家通过对象。 However, the controls seem very jagged because if the player is, for example, trying to move left and up while in contact with a wall, the character remains still. 然而,控件似乎非常锯齿状,因为如果玩家在与墙壁接触时试图向左和向上移动,则角色保持静止。 In other words, the character can't touch a wall and still move parallel to it. 换句话说,角色不能触及墙壁并仍然平行于墙壁移动。 In order to fix this problem I created four rectangles drawn on top of the player object that I use to determine the side that is colliding with another object, so that instead of restoring the (x,y) coordinates I can restore x or y depending on which side is colliding. 为了解决这个问题,我创建了四个在玩家对象顶部绘制的矩形,用于确定与另一个对象碰撞的一侧,这样我可以恢复x或y,而不是恢复(x,y)坐标。在哪一方碰撞。 For example, if I know that the top is colliding with something, then I can restore the y position and allow the x to change freely. 例如,如果我知道顶部与某些东西发生碰撞,那么我可以恢复y位置并允许x自由变化。 Below you can see a picture of the player object with the rectangles drawn on it: 下面你可以看到播放器对象的图片,上面画着矩形:

在此输入图像描述

This idea is very unreliable, specially in corners where it is difficult to determine from which side the collision is coming from. 这种想法非常不可靠,特别是在难以确定碰撞来自哪一侧的角落。 So, my question is, how can I reliably determine which side of a rectangle is colliding with another rectangle in java using swing? 所以,我的问题是, 如何使用swing可靠地确定矩形的哪一侧与java中的另一个矩形相撞? Or, do you have a better alternative to my approach towards detecting collisions? 或者,您是否有更好的替代方法来检测碰撞?

Note that player movement is completely free, my implementation doesn't snap the character from tile to tile. 请注意,玩家移动是完全免费的,我的实现不会将角色从一个拼贴到另一个拼贴。 And that the distance between tiles is 32x32 pixels, and the player is 30x30 pixels. 并且瓷砖之间的距离为32x32像素,播放器为30x30像素。

Thank you for the help. 感谢您的帮助。 If you have any extra questions about my implementation, please let me know. 如果您对我的实施有任何其他疑问,请告诉我。

rects.stream().forEach((re) ->
{
    double w = 0.5 * (re.width + player.width);
    double h = 0.5 * (re.height + player.height);
    double dx = re.getCenterX() - player.getCenterX();
    double dy = re.getCenterY() - player.getCenterY();

    if (abs(dx) < w && abs(dy) < h)//collision
    {
        double wy = w * dy;
        double hx = h * dx;
        if (wy >= hx)
            if (wy >= -hx)//top of block
                player.y = re.y - player.height;//align edges
            else//right of block
                player.x = re.x + re.width;//align edges
        else
            if (wy >= -hx)//left of block
                player.x = re.x - player.width;//align edges
            else//bottom of block
                player.y = re.y + re.height;//align edges
    }
});

This will find which side is being hit and correct the player's position to line up with that side's edge. 这将找到被击中的哪一方并纠正玩家的位置以与该方的边缘对齐。 I am using a slightly more complicated version of this code in my game, but the idea is the same. 我在游戏中使用了这个代码稍微复杂一点的版本,但想法是一样的。 (do this AFTER you reposition your player in your updating method.) (在更新方法中重新定位播放器后执行此操作。)

Kind of simple, take a collision that happens at the bottom right corner of some rectangle A by B, and you want to find out if B collided into A more from the right, or more from the bottom. 有点简单,在一个矩形A到B的右下角发生碰撞,你想知道B是否从右边碰到了A,或者从底部碰到了更多。 All you have to do is measure how many pixels the top y coordinate of B is above A's lowest y coordinate, and measure how many pixels B's far left x coordinate is to the left of A's far right x coordinate. 您所要做的就是测量B的前y坐标高于A的最低y坐标的像素数,并测量B的最左侧x坐标位于A的最右侧x坐标左侧的像素数。

If there's more of a difference between the x coordinates than the y coordinates then it's a collision from the bottom, otherwise it's a collision from the side. 如果x坐标与y坐标之间的差异更大,那么它就是来自底部的碰撞,否则它就是来自侧面的碰撞。

One really simple solution (given what you already have written) is to split the code for Test-and-Move into two checks. 一个非常简单的解决方案(根据您已编写的内容)是将Test-and-Move的代码拆分为两个检查。

//update.player.x.position
if (playerRectangle.intersects(wallRectangle)) {
  player.restorePreviousPosition();
}

//update.player.y.position
if (playerRectangle.intersects(wallRectangle)) {
  player.restorePreviousPosition();
}

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

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