java - 静止物体与运动物体的碰撞

标签 java swing collision maze

我正在构建一个迷宫游戏,这里有一个简单的 map ......

直到没有问题,但我的问题是碰撞

这是我的 map :

enter image description here

这里我用以下代码自己构建了 map :

package maze;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;

public class Maze1 extends GameObject{

    public Maze1(int x, int y, ID id) {
        super(x, y, id);
    }

    public void tick() {

    }

    public void render(Graphics g){
        Font fnt = new Font("arial", 1, 25);
        g.setFont(fnt);
        g.drawString("Level : 1",165 , 433);

        //x, y, WIDTH, HEIGHT
        g.setColor(Color.darkGray); 
        g.fillRect(65, 65, 130 ,15); 
        g.fillRect(0, 130, 145 ,15); 
        g.fillRect(195, 195, 400 ,15);
        g.fillRect(65, 195, 80 ,15); 
        g.fillRect(130, 260, 80 ,15); 
        g.fillRect(65, 325, 195 ,15); 
        g.fillRect(325, 325, 80 ,15); 

        // x, y, WIDTH, HEIGHT

        g.fillRect(195, 130, 80 ,80); 
        g.fillRect(260, 0, 145 ,80);  

        //x, y, HEIGHT, WIDTH

        g.fillRect(65, 145, 15 ,130); 
        g.fillRect(195, 65, 15 ,195); 
        g.fillRect(260, 260, 15 ,130);
        g.fillRect(325, 130, 15 ,80); 
        g.fillRect(325, 260, 15 ,65); 


        g.setColor(Color.black);
        g.fillRect(0, -20, 500 ,32); //x, y, WIDTH, HEIGHT
        g.fillRect(0, 390, 500 ,15); 
        g.fillRect(0, Game.HEIGHT - 41, 500 ,30); 
        g.fillRect(-20, 0, 32 ,500);
        g.fillRect(Game.WIDTH -18, 0, 32 ,340);
        g.fillRect(Game.WIDTH -18, 400, 32 ,100);
    }
}

此碰撞代码适用于右上角矩形

我尝试了两种不同类型的碰撞代码,但都不起作用

碰撞代码:

public void collision() {
    if(this.getX() >=229 && this.getY() <= 79) {
        if(this.getX() >=229) {
            this.setVelX(0);
            this.setVelY(0);
            this.setX(this.getX() -1);
        }

        if(this.getY() <= 79){
            this.setVelX(0);
            this.setVelY(0);
            this.setY(this.getY() +1);
        }       
    }

这里,当玩家从左侧击中矩形时,玩家会向下移动,而当玩家从底部击中矩形时,玩家会向左移动。

我已经用 if, else if 语句尝试了相同的代码,但它仍然不起作用。当玩家击中左侧时,它可以正常工作,但是当玩家从底部击中矩形时,它会传送到矩形的边缘。

我希望我的描述足以让您了解我的情况。

提前致谢!

最佳答案

对于碰撞检测,我建议将 map 数据保存在矩形列表中。像这样的东西:

public class Rect {
    public int topLeftX;
    public int topLeftY;
    public int width;
    public int height;

    public Rect(int x, int y, int w, int h){
        topLeftX = x;
        topLeftY = y;
        width = w;
        height = h;
    }


    //Ignore the code below here for now


    public boolean collidingWith(int x, int y, int width, int height){ 
        Rect r = new Rect(x, y, width, height);
        boolean rLeftInWidth = r.topLeftX > topLeftX && r.topLeftX < topLeftX + width;
        boolean rRightInWidth = r.topLeftX + r.width > topLeftX && r.topLeftX + width < topLeftX + width;
        boolean rTopInHeight = r.topLeftY > topLeftY && r.topLeftY < topLeftY + width;
        boolean rBottomInHeight = r.topLeftY + r.width > topLeftY && r.topLeftY + width < topLeftY + width;


        if(rLeftInWidth || rRightInWidth){
            //If there is horizantal overlap between the other rectangle and this one
            if(rTopInHeight || rBottomInHeight){
                //If there is also vertical overlap then we must be colliding
                return true;
            }
        }
        return false;
    }
}

然后将矩形保存在数组或某种集合中,ArrayList 可能是最简单的。

ArrayList<Rect> wallData = new ArrayList<Rect>();

然后您可以添加 map 数据。这是取自你的矩形绘画:

g.fillRect(65, 65, 130 ,15);

它变成一个矩形,具有相同的参数。您甚至可以在填充矩形并重复使用之前执行此操作。

wallData.add(new Rect(65, 65, 130, 15));
Rect r = wallData.get(0);
g.fillRect(r.topLeftX, r.topLeftY, r.width, r.height);

既然您已经有了这些数据,那么如何使用它呢?当您想要检查碰撞时,只需循环遍历矩形列表并检查玩家是否发生碰撞。

for(Rect rectangle: wallData){
    if(rectangle.collidingWith(<playerX>, <playerY>, <playerWidth>, <playerHeight>)){
        //Your player is colliding with a rectangle!
    }
}

还记得我之前告诉你忽略的那部分吗?现在让我们回顾一下。 我发誓,它比看起来更简单!

    public boolean collidingWith(int x, int y, int width, int height){ 
        Rect r = new Rect(x, y, width, height);
        boolean rLeftInWidth = r.topLeftX > topLeftX && r.topLeftX < topLeftX + width;
        boolean rRightInWidth = r.topLeftX + r.width > topLeftX && r.topLeftX + width < topLeftX + width;
        boolean rTopInHeight = r.topLeftY > topLeftY && r.topLeftY < topLeftY + width;
        boolean rBottomInHeight = r.topLeftY + r.width > topLeftY && r.topLeftY + width < topLeftY + width;


        if(rLeftInWidth || rRightInWidth){
            //If there is horizantal overlap between the other rectangle and this one
            if(rTopInHeight || rBottomInHeight){
                //If there is also vertical overlap then we must be colliding
                return true;
            }
        }
        return false;
    }
}

我们首先确定是否水平重叠。例如,以下内容在水平方向上重叠,但在垂直方向上不重叠。

=-----=
-     -
-     -
-------
   +------
   -     -
   -     -
   -------

您可以看出,因为带加号的角位于带等号的角之间。这四个 boolean 值仅保存我们的角是否位于另一个对象的角之间。

boolean rLeftInWidth = r.topLeftX > topLeftX && r.topLeftX < topLeftX + width;

如果我们的左上角位于其他矩形的左上角和右上角之间,则情况成立。然后我们对右角也这样做。如果其中任何一个为真,那么我们就水平重叠了!

从那里,我们只需检查它是否水平和垂直重叠。如果是,那就是碰撞,就像这样!

-------
-     -
-   ------
-----    -
    -    -
    ------

现在,当您意识到您的玩家发生碰撞时,您会做什么?这需要一些工作,但没什么特别的。在通过将玩家的速度添加到其位置来移动玩家之前,只需保存他们的位置即可。

private int playerX;
private int playerY;

<method where you change it>{
    playerX = <playerX>;
    playerY = <playerY>;
    <change their location according to velocity>
}

现在,如果玩家与墙壁发生碰撞,只需将其位置设置回您刚刚保存的值,并将其速度设置为 0!

设置起来有点复杂,但是一旦你开始使用,这就是一个很好的解决方案。

在这个答案中,我在<>之间放了一堆东西。这仅仅意味着您需要该值,或者这就是它所说的发生的地方。

希望这对您有帮助!如果您有任何疑问,请随时提问,我很乐意为您提供更多帮助。碰撞检测是一个复杂的课题,有很多方法。这通常是我认为对于简单应用程序来说最简单的一种。

此方法与原始方法相比的优点:

  • 您可以在绘制之前设置矩形,并将其用于绘制和碰撞检测。

如果您创建了矩形列表,则可以使用循环来绘制它们:

for(Rect r: wallData){
    g.fillRect(r.topLeftX, r.topLeftY, r.width, r.height);
}
  • 易于编辑:如果您决定更改 map ,您只需更改一些矩形的宽度、高度和位置,而不必通过一堆 if 语句来尝试确定这是否是正确的。改变。 (我以前经历过)

  • 不易出错:为每面墙设置一些矩形比使用大量 if 语句要容易得多。

此方法与原始方法的缺点

  • 这个效率较低——需要更多的操作来检查玩家是否与矩形碰撞,而不是 2 个 if。此外,可能存在玩家无法碰撞的矩形。但是,效率损失非常小,尤其是在 map 中矩形数量较少的情况下。

  • 这个比较复杂。最好了解您使用的代码,而不是盲目复制粘贴。如果你需要改变,如果你不理解的话,那就更难了。 (并不是说你不这样做,只是可能会有点困难。)

关于java - 静止物体与运动物体的碰撞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50935053/

相关文章:

java - 在碰撞java中删除敌人和子弹

jquery .animate() 碰撞检测

java - 具有特定注释的参数的方法的 AspectJ 切入点

java - 如果当前线程崩溃,读写锁会发生什么

java - 如何创建 7 个字符的字母数字唯一 ID?

java - Java 初始屏幕上的取消按钮

java - swing:让窗口永远不会失去焦点

swift - 如何使用 Swift 在 SpriteKit 中旋转 SKPhysicsBody

Java:某些情况下的 ClassCastException

java - 在多行 JTextField 中更改光标垂直对齐方式