Java 2D碰撞

时间:2011-10-16 11:04:05

标签: java collision-detection

  

可能重复:
  Java 2D Collision?

嘿伙计们,我有另外一篇关于此事的帖子已经死了所以我想我会尝试得到一些关于此的新答案。

我正试图让我的碰撞检测工作。当我来到我的地图块时,我的碰撞检测工作正常,当我只是向上或向下并从顶部或底部击中一个块时,我的碰撞很好。但是,当我向上或向下或向左或向下按住并从顶部或底部击中一个街区时,它将以有趣的方向前进。

我的小视频演示(对不起,如果不清楚):http://www.youtube.com/watch?v=6ILccRtw8ME希望这会有所帮助。

如果您没有在这里观看视频,那么我将使用地图的图片:

enter image description here

这是我当前的碰撞代码:

    public void checkCollision() {
    Rectangle player_rectangle = new Rectangle(player.getX(),player.getY(),32,32);

    for(Wall wall : walls) {

        Rectangle wall_rectangle = new Rectangle(wall.getX(), wall.getY(), 32,32);

        if (player_rectangle.intersects(wall_rectangle)) {
            Rectangle intersection = (Rectangle) player_rectangle.createIntersection(wall_rectangle);


            if (player.xspeed < 0 && player.x >= intersection.x) {
                player.x += intersection.getWidth();
            } else {

            if (player.xspeed > 0 && player.x <= intersection.x) {
                player.x -= intersection.getWidth();
            } else {

            if (player.yspeed < 0 && player.y >= intersection.y) {
                player.y += intersection.getHeight();
            }else {

            if (player.yspeed > 0 && player.y <= intersection.y) {
                player.y -= intersection.getHeight();
            }
            }
            }
            }



            Print(Integer.toString(intersection.width) + ", " + Integer.toString(intersection.height));

        }

    }

}

感谢所有帮助。

2 个答案:

答案 0 :(得分:3)

这是我第一次尝试回答有关StackOverflow的问题,请耐心等待。我将尝试通过首先诊断问题,找到可能导致问题的症状并最后提出解决方案并查看它是否适合您来构建此答案。

首先,让我使用正确的缩进级别格式化您的代码,以便我们更清楚地了解正在发生的事情。

public void checkCollision() {
    Rectangle player_rectangle = new Rectangle(player.getX(),
            player.getY(), 32, 32);

    for (Wall wall : walls) {

        Rectangle wall_rectangle = new Rectangle(wall.getX(), wall.getY(),
                32, 32);

        if (player_rectangle.intersects(wall_rectangle)) {
            Rectangle intersection = (Rectangle) player_rectangle
                    .createIntersection(wall_rectangle);

            if (player.xspeed < 0 && player.x >= intersection.x) {
                player.x += intersection.getWidth();
            } else {

                if (player.xspeed > 0 && player.x <= intersection.x) {
                    player.x -= intersection.getWidth();
                } else {

                    if (player.yspeed < 0 && player.y >= intersection.y) {
                        player.y += intersection.getHeight();
                    } else {

                        if (player.yspeed > 0 && player.y <= intersection.y) {
                            player.y -= intersection.getHeight();
                        }
                    }
                }
            }

            Print(Integer.toString(intersection.width) + ", "
                    + Integer.toString(intersection.height));

        }

    }

}

现在我们已经这样做了,你正在做的事情变得更加清晰。我注意到的第一件事是你正在嵌套条件语句。澄清一下,你这样做:

    if (condition){
    // do something
    else{
        if(anotherCondition){
            // do something
            else{
                //etc
            }
        }
    }
}

你应该做的是在一行中使用多个条件语句:

if (condition){
    //do something
}

if (anotherCondition){
    //do something else
}

//etc

这是因为如果您有两个案例,例如您在左下角,则需要执行左侧交叉点的条件以及底部的交叉点。但是,这与您的示例无关,因为您单独浏览每个墙。

那为什么这很重要?

嗯,在我看来,如果不满足第一个条件,那么所有其他条件都不会执行。如果player.xspeed < 0 && player.x >= intersection.x返回true,那么即使嵌套在其中的其他3个语句返回true,它们也不会被执行,因为它依赖于第一个语句false。因此,当你前往两个或多个案例的边缘时,你只能执行其中一个。

因此,基于上述所有内容,我提出的解决方案是:

public void checkCollision() {
        Rectangle player_rectangle = new Rectangle(player.getX(),
                player.getY(), 32, 32);

        for (Wall wall : walls) {

            Rectangle wall_rectangle = new Rectangle(wall.getX(), wall.getY(),
                    32, 32);

            if (player_rectangle.intersects(wall_rectangle)) {
                Rectangle intersection = (Rectangle) player_rectangle
                        .createIntersection(wall_rectangle);

                if (player.xspeed < 0 && player.x >= intersection.x) {
                    player.x += intersection.getWidth();
                } 

                if (player.xspeed > 0 && player.x <= intersection.x) {
                    player.x -= intersection.getWidth();
                }

                if (player.yspeed < 0 && player.y >= intersection.y) {
                    player.y += intersection.getHeight();
                }

                if (player.yspeed > 0 && player.y <= intersection.y) {
                    player.y -= intersection.getHeight();
                }

                Print(Integer.toString(intersection.width) + ", "
                        + Integer.toString(intersection.height));

            }

        }

    }

试一试,看看它是否有效。如果没有,那么我们可以从那里开始,看看如何改进和解决您的问题。

答案 1 :(得分:0)

我建议为checkCollision需要处理的所有不同状态编写一系列单元测试。 这样,您将:

  • 轻松找出导致块跳转的特定输入(因为单元测试很短并且包含良好)
  • 确保未来的更改不会破坏此功能(因为每次构建都会运行单元测试)

对此的样本单元测试看起来像这样:

public class CollisionTests {

    @Test
    public void hitFromLeftHeadOn() throws Exception {
        List<Wall> walls = Lists.newArrayList(
            new Wall( ... ), // south wall
            new Wall( ... ), // east wall
            // etc.
        );
        Player player = new Player(...);

        // Set player to collide with the east wall head on
        player.setX(...);
        player.setY(...);
        player.setXSpeed(...);
        player.setYSpeed(...);

        checkCollision();

        // Now check if the checkCollision method worked properly
        assertEquals("Player's x coordinate should be set to ...", ..., player.getX());
        assertEquals("Player's y coordinate should be set to ...", ..., player.getY());
    }

一旦你编写了一个测试,就可以轻松添加更多测试。您可以创建各种辅助方法来创建墙,播放器等,以便每个测试用例缩小到几行。

Here's a tutorial on unit testing.

作为一个额外的奖励,如果你写一个单元测试,你也会写一个SSCCE:)