使用重力进行2D碰撞检测 - JavaScript

时间:2012-12-09 08:11:30

标签: javascript html5 canvas 2d collision-detection

我正在尝试使用HTML5画布制作游戏以获得乐趣,但由于重力,我无法检测两个精灵之间的碰撞。

我的Player类中有一个tick()方法,在每个刻度线上,分别通过velocityX和velocityY增加玩家的x和y坐标。然后,我将gravity重力加到velocityY上。然后我想检查播放器和屏幕上的块之间的碰撞,这些块在屏幕底部排成一行并存储在一个数组中。

这是代码:

Player.prototype.tick = function() {

    this.x += this.velocityX;
    this.y += this.velocityY;
    this.velocityY += GRAVITY;

    var blocks = world.getOnScreenBlocks();
    for (var i=0; i<blocks.length; i++) {
            //Check for collision of this object (Player) with blocks[i]
        }
    }
}

我花了几个小时试图让碰撞检测工作但却放弃了。我知道如何将玩家的坐标与每个区块的坐标进行比较以检测碰撞,但问题是在发生碰撞时进行调整。

如果我在块的顶部检测到碰撞,我可以将velocityY设置为0,从而使玩家停止垂直移动。但是,在下一个勾选中,由于GRAVITY被添加到它上面,velocityY将增加,导致再次检测到碰撞,并且玩家在许多滴答之后慢慢地通过该块。

如果我在碰撞时将velocityY设置为0并且将玩家的位置固定在块的正上方,那么它会稍微有效,除非由于重力试图将其推下而在站上阻挡时会检测到持续的碰撞。

这是我在块的四个边上进行碰撞检测的最接近的地方:

var blocks = world.getOnScreenBlocks();
for (var i=0; i<blocks.length; i++) {
    var block = blocks[i];
    var left1 = this.x;
    var left2 = block.getX();
    var right1 = this.x + this.sprite.getWidth();
    var right2 = block.getX() + block.getSprite().getWidth();
    var top1 = this.y - this.sprite.getHeight();
    var top2 = block.getY() - block.getSprite().getHeight();
    var bottom1 = this.y;
    var bottom2 = block.getY();

    //Check for collision at top
    if (this.velocityY > 0) {
        if (left1 < right2 && right1 > left2 && bottom1 >= top2 && bottom1 <= bottom2) {
            this.y = top2;
            this.velocityY = 0;
        }
    }

    //Check for collision at bottom
    else if (this.velocityY < 0) {
        if (left1 < right2 && right1 > left2 && top1 <= bottom2 && top1 >= top2) {
            this.y = bottom2 + this.sprite.getHeight();
            this.velocityY = 0;
        }
    }

    //Check for collision on right
    if (this.velocityX > 0) {
        if (top1 < bottom2 && bottom1 > top2 && right1 >= left2 && right1 <= right2) {
           this.x = left2 - this.sprite.getWidth();
            this.velocityX = 0;
        }
    }

    //Check or collision on left
    else if (this.velocityX < 0) {
       if (top1 < bottom2 && bottom1 > top2 && left1 <= right2 && left1 >= left2) {
            this.x = right2;
            this.velocityX = 0;
        }
    }
}

这有点奏效,但真的很糟糕。我真的想避免在发生碰撞时设置精灵的x和y坐标,并设置速度,因为我觉得这样会不那么毛刺。

我也试过设置布尔值来进行碰撞,以便在检测到碰撞但没有任何作用时不添加重力。有没有一种标准的,正确的方法呢?请帮忙。

另外,为了提高效率,我真的希望它只是通过循环来检查玩家是否移动时的碰撞,但我不确定如何因为由于重力导致速度Y总是高于零。

感谢。

编辑:我应该在上面的第二个例子中包括,播放器和块x和y坐标基于左下角而不是典型的左上角。我之所以这样做是因为我的精灵高度不同,我希望在精灵脚与地面碰撞的底部发生碰撞。

1 个答案:

答案 0 :(得分:0)

你是否知道 isGrouned var会知道何时在你的播放器上施加重力,只有当 isGrounded == false 时才能应用重力。

你处于矢量环境中,你可以进行一种投机碰撞(here),这很难理解,但你只需要知道你的玩家的n + 1位置和chekc if他会碰撞。

如果您可以阅读有关碰撞的this french article,那么在许多情况下它都很有用。