Java - 碰撞检测(故障)

10

我正在高中的毕业项目中开发一个平台游戏。 然而... 我所使用的碰撞检测系统基本上是检查角色的特定部分是否与另一个块相交。

碰撞似乎工作正常,但导致一些错误,比如玩家从侧面撞击时有点卡住或者减速,或者在同时按下上下左右箭头时被弹起。

我的问题是:如何改进碰撞代码以避免此类故障并具有类似于“滑动”碰撞的效果?

这是我想要实现的碰撞效果:
(https://i.imgur.com/KB1M3bt.mp4)
enter image description here

(https://i.imgur.com/I44fmPc.mp4) enter image description here

这是边界的预览

enter image description here


这是实际在游戏中的预览 (点击查看更好的质量) enter image description here
我用于碰撞检测的代码: (tempObject是玩家与之相交的块)

if(getBoundsTop().intersects(tempObject.getBoundsBottom())){
    y = tempObject.getY() + height;
    velY = 0;
    System.out.println("Top collision");
}

if(getBoundsBottom().intersects(tempObject.getBoundsTop())){
    y = tempObject.getY() - height;
    velY = 0;
    falling = false;
    jumping = false;
    //isOnBlock = true;
} else {
    falling = true;
    //isOnBlock = false;
}

if(getBoundsRight().intersects(tempObject.getBoundsLeft())){
    x = tempObject.getX() - this.width;
}


if(getBoundsLeft().intersects(tempObject.getBoundsRight())){
    x = tempObject.getX() + this.width;
}

这里是绑定方法:

public Rectangle getBounds() { return new Rectangle( (int)x, (int)y, (int)width, (int)height ); }

    public Rectangle getBoundsTop() {
        return new Rectangle(
                (int)x, 
                (int)y, 
                (int)(width-(width*0.01f)), 
                (int)(height/2)
        );
    }
    public Rectangle getBoundsBottom() {
        return new Rectangle(
                (int)x,
                (int)(y+(height/2)),
                (int)(width-(width*0.01f)),
                (int)(height/2)
        );
    }

    public Rectangle getBoundsLeft() {
        return new Rectangle(
                (int)x,
                (int)y, 
                (int)((int)width*0.15f), 
                (int)height
        );
    }

    public Rectangle getBoundsRight() {
        return new Rectangle(
                (int) 
                ((int)x+(width-(width*0.15f))), 
                (int)y, 
                (int) ((int)width*0.15f), 
                (int)height
        );
    }

编辑:我正在使用恒定加速度速度来设置速度

acc = 2.5f;
MAX_SPEED = 10;


if(Game.keyDownMap.containsKey(KeyEvent.VK_A)){

    setVelX(getVelX() - acc);
    if(getVelX() < -MAX_SPEED)
        setVelX(-MAX_SPEED);

} else if(Game.keyDownMap.containsKey(KeyEvent.VK_D)){

    setVelX(getVelX() + acc);
    if(getVelX() > MAX_SPEED)
        setVelX(MAX_SPEED);

}

2
非常好的提问!(+1):您提供了一个解释清晰的问题,包括网站上的图像/动画和详细格式良好的代码示例。在我看来,这应该作为编写新问题时参考的模板。 - Rann Lifshitz
1
从动画中可以看出,当方块与物体碰撞时,它仍然保持移动。在这种情况下,您可能希望一旦发生碰撞就停止其在给定方向上的移动,但不重置位置。尝试调整检查碰撞和更改角色位置的位置。此外,如果您想要更平滑的移动,可以添加加速度而不是立即更改速度。这将使移动略微平滑,但您需要根据自己的目的进行调整。 - Shadowzee
你使用什么来表示速度?可以提供代码中与此相关的部分吗? - Tschallacka
当检测到水平碰撞时,您没有将“velX”设为0。 - Herr Derb
我刚把它设置为0,然后发现了另一件事;当我以最大速度行进并试图撞击一个方块时,我会穿过它 :D(并非总是发生) - Feelsbadman
显示剩余3条评论
1个回答

1

当发生侧向碰撞时,您需要将侧向速度设为零。这样只会有垂直速度,我假设会设置setVelY();

if(getBoundsRight().intersects(tempObject.getBoundsLeft())){
    x = tempObject.getX() - this.width;
    setVelX(0);
}


if(getBoundsLeft().intersects(tempObject.getBoundsRight())){
    x = tempObject.getX() + this.width;
    setVelX(0);
}

此外,您需要在按键时检查是否存在碰撞状态。 您可能希望创建一个方法来设置当前是否与某些内容相交,并在每个游戏周期更新它。
if(Game.keyDownMap.containsKey(KeyEvent.VK_A) && !isIntersectingLeft()){

    setVelX(getVelX() - acc);
    if(getVelX() < -MAX_SPEED)
        setVelX(-MAX_SPEED);

} else if(Game.keyDownMap.containsKey(KeyEvent.VK_D) && !isIntersectingRight()){

    setVelX(getVelX() + acc);
    if(getVelX() > MAX_SPEED)
        setVelX(MAX_SPEED);

}

如果你想要一点弹性,你可以在不同的方向上设置一点速度。
if(getBoundsRight().intersects(tempObject.getBoundsLeft())){
    x = tempObject.getX() - this.width;
    if(this.getVelX() > 0) {
        setVelX(10);
    }
}


if(getBoundsLeft().intersects(tempObject.getBoundsRight())){
    x = tempObject.getX() + this.width;
    if(this.getVelX() > 0) {
       setVelX(-10);
    }
}

1
似乎比以前工作得更好:D 我想我将不得不玩弄一下边界,以避免玩家在撞到带有角落的方块时被抛出。 - Feelsbadman
你可以使用多个边界框。你有一个大的边界框,它包围着所有小的边界框。如果大的边界框发生碰撞,那么你就迭代在这个大的边界框中的小边界框集合,以查看是否存在“真正”的碰撞。这样你就可以包含圆形和三角形特征。 - Tschallacka
如果玩家与绿色方块发生碰撞,则迭代红色方块以检查碰撞,然后迭代黄色方块以迭代碰撞。但是,您只需要外部边缘上的命中框。 - Tschallacka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接