简体   繁体   English

具有重力的2D碰撞检测-JavaScript

[英]2D Collision Detection With Gravity - JavaScript

I am trying to make a game using the HTML5 canvas for fun but I am having trouble detecting collisions between two sprites because of gravity. 我正在尝试使用HTML5画布制作游戏,但由于重力原因,我无法检测到两个精灵之间的碰撞。

I have an tick() method in my Player class where, on each tick, increments the player's x and y coordinate by its velocityX and velocityY respectively. 我的Player类中有一个tick()方法,在每个刻度上,分别将其x和y坐标分别按其velocityX和velocityY递增。 Then, I add gravity to velocityY. 然后,将重力添加到速度Y。 I then want to check for collisions between the player and the blocks on screen which are at lined up on the bottom of the screen and stored in an array. 然后,我要检查播放器和屏幕上的块之间的冲突,这些块在屏幕底部对齐并存储在数组中。

This is the code: 这是代码:

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]
        }
    }
}

I have spent a few hours trying to get collision detection to work but gave up. 我花了几个小时试图使碰撞检测正常工作,但放弃了。 I know how to compare the player's coordinates with each block's coordinates to detect collisions but the problem is adjusting in the case of a collision. 我知道如何将玩家的坐标与每个块的坐标进行比较以检测碰撞,但是在发生碰撞的情况下问题正在调整。

If I detect a collision at the top of the block I can set velocityY to 0 causing the player to stop moving vertically. 如果我在方块的顶部检测到碰撞,则可以将VelocityY设置为0,从而导致玩家停止垂直移动。 However, in the next tick, velocityY will increase due to GRAVITY being added onto it causing a collision being detected again and the player to slowly pass through the block after many ticks. 但是,在下一个滴答声中,由于将GRAVITY添加到了速度Y上,因此会增加速度Y,从而再次检测到碰撞,并且玩家在许多滴答声之后缓慢通过了障碍物。

If I set velocityY to 0 on collision AND fix the player's position to be just above the block, it will somewhat work except there will be constant collisions detected while standing on the block due to gravity trying to push it down. 如果我在碰撞时将VelocityY设置为0并将玩家的位置固定在方块上方,则它将有些起作用,除了在重力作用下试图将其推下而站在方块上时会不断检测到碰撞。

This is the closest that I've gotten to getting collision detection on all four sides of a block: 这是我在块的所有四个侧面上都获得碰撞检测的最接近的东西:

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

This somewhat works but is really glitchy. 这在某种程度上可行,但确实存在故障。 I really want to avoid setting the x and y coordinates the sprite when a collision occurs and just set the velocities because I think that would be less glitchy. 我真的想避免在发生碰撞时将x和y坐标设置为sprite,而只是设置速度,因为我认为这样会减少毛刺。

I've also tried setting booleans for collision so to not add gravity if a collision was detected but nothing works. 我还尝试为碰撞设置布尔值,以便在检测到碰撞但不起作用的情况下不增加重力。 Is there a standard, proper way of doing this? 是否有标准,适当的方法来做到这一点? Please help. 请帮忙。

Also, to make it more efficient, I would really like it to only go through the loop to check for collisions if the player is moving but i'm not sure how because the velocityY will always be above zero due to gravity. 另外,为了提高效率,我真的希望它只循环检查玩家是否在移动是否发生碰撞,但是我不确定这样做的原因,因为在重力作用下,speedY总是大于零。

Thanks. 谢谢。

EDIT: I should include that in my second example above, the player and blocks x and y coordinates are based on the bottom-left corner and not the typical top-left corner. 编辑:我应该在上面的第二个示例中包括该播放器和块x和y坐标是基于左下角而不是典型的左上角。 I did this due to my sprites being different heights and I wanted to get collision to work at the bottom where the sprites feet collide with the ground. 我之所以这样做是因为我的精灵的高度不同,所以我想让碰撞在精灵脚与地面碰撞的底部起作用。

Do you though about a isGrouned var who will know when apply the gravity on your player, with it you can apply gravity only when isGrounded == false . 您是否知道isGrouned变量 ,该变量会知道何时在您的播放器上施加重力,因此只有在isGrounded == false时您才能施加重力。

You are in a vector environment, you can make a kind of speculative collision ( here ), it can be difficult to understand, but you just have to know the n+1 position of your player and chekc if he will be in collision. 您处于向量环境中,可以进行一种推测性碰撞( 在此处 ),这很难理解,但是您只需要知道玩家的n + 1位置并检查他是否会发生碰撞。

If you can read this french article about collision, it can be usefull in many case. 如果您可以阅读有关碰撞的法语文章 ,那么在许多情况下它可能会很有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM