当前位置: 首页 > 知识库问答 >
问题:

静止物体和运动物体之间的碰撞

宣望
2023-03-14

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

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

这是我的地图:

在这里,我用以下代码自己构建了地图:

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语句尝试过相同的代码,但仍然不起作用。当玩家点击左侧时,它可以完美地工作,但当玩家从底部点击矩形时,它会传送到矩形的边缘。

我希望我的描述足够清楚,能让你描绘出我的处境。

提前感谢!

共有1个答案

宁浩博
2023-03-14

对于碰撞检测,我建议将地图数据保留在矩形列表中。类似于:

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

然后,您可以添加地图数据。这是从您的矩形绘画中获取的:

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

>

  • 易于编辑:如果你决定改变你的地图,你只需要改变一些矩形的宽度、高度和位置,而不是通过一堆if语句来判断这是否是正确的改变。(我以前经历过)

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

    这种方法与原始方法的缺点

    >

  • 这一个效率较低——有更多的操作用于检查播放器是否与矩形碰撞,而不是2个ifs。此外,可能还有玩家无法碰撞的矩形。然而,效率上的损失很小,尤其是在地图中矩形数量较少的情况下。

    这个更复杂。最好了解您使用的代码,而不是盲目地复制粘贴。如果你需要做出改变,如果你不理解,就会更难。(并不是说你没有,只是可能会更难一些。)

  •  类似资料:
    • 我知道关于这个话题已经有了一些答案,但我不太清楚如何测量相机和物体之间的距离。 我的目标是: 我用OpenCV通过颜色检测成功地追踪了一个红色的球。现在我试着在红球的中间点一个激光。当红球移动时,激光器应始终跟随红球。我用一个小伺服电机来转动激光。 我在想,如果我能测量物体和相机之间的距离,我就能计算出伺服需要转动的角度。。。 我试图跟踪卡梅伦·洛厄尔·帕尔默的帖子。 我所做的: 我校准了我的Pi

    • 问题内容: 我主要专注于图形方面,以创建一些2DGame。我看过/看过几本教程,但是没有一部教程那么令人满意。我已经有一个玩家(一个正方形)在屏幕上移动并与其他正方形碰撞。重力等。 如果在屏幕上看到的对象太多(30 * 20),则一切正常。但是,如果我将其增加到300 * 300,则该程序开始运行非常慢,因为它必须检查许多对象。 我真的不知道Minecraft之类的游戏如何与ALL THOSE块一

    • 当我在中创建一个场景时,我经常需要两个节点在完全相同的或位置来创建一面墙。我添加了矩形物理体。它们都没有任何摩擦。 当我使一个spritendode在这些碰撞体上移动时(我对物理体使用冲量),它的行为就像在两个矩形之间有一个屏障,我需要“推”节点或使其跳过边界。正如我所说的,这些节点彼此完全一致,因此节点应该能够平滑地通过它们。 有什么建议吗? 如果你需要我正在使用的任何代码/图片,请询问。 编辑

    • 有人对如何处理Unity中缺少碰撞的快速移动物体有任何建议吗?我正在为移动设备创建一个突破游戏,发现当桨移动得非常快时,它会错过与球的碰撞。我将碰撞更改为连续检测,但这会引发奇怪的行为,例如碰撞时桨被推倒。 我还尝试使用dontgothrough脚本使其适用于2D碰撞器,但没有成功。有人有什么建议吗?

    • 本文向大家介绍Javascript 多物体运动的实现,包括了Javascript 多物体运动的实现的使用技巧和注意事项,需要的朋友参考一下 我们先来看下之前的运动的代码,是否支持多物体运动,会出现怎么样的问题。 以下是Javascript 代码: 此时当鼠标移入到第一个div 时,他是正常运行的。但是如果现在又移动到第二个或者第三个div时候就会出现bug。 image 这个是什么原因呢? 看图可

    • 我有两个身体,都是动态的,其中一个我已经关闭了重力,只有当它被我的另一个身体击中时才想打开它。我知道我可以设置自己的联系人侦听器,但我想指定一个动作,只有当两个特定的身体接触时。 有人有指导吗?