【问题标题】:JS: Collision Detection doesn't work when Ball is moving fasterJS:当球移动得更快时,碰撞检测不起作用
【发布时间】:2018-03-23 19:41:43
【问题描述】:

我目前正在尝试学习 JavaScript,并遵循了有关编程 Breakout 游戏的教程。我在教程之后添加了一些东西。我添加的一件事是随着比赛的进行,球会变得更快。现在我有以下问题。

我的球拍厚度为 10 像素,但在某些时候球的移动速度超过了每帧/更新 10 像素。正因为如此,它经常直接穿过桨板,因为它会反弹。我已经将 FPS/UPS 从 60 翻倍到 120,并将球速除以 2。

当然我可以进一步提高 fps,但我希望有一个更高效/优雅的版本来处理这个问题。

这是我用来让球从桨上反弹的函数:

function ballPaddleHandling() {
    var paddleTopEdgeY = canvas.height-PADDLE_DIST_FROM_EDGE;
    var paddleBottomEdgeY = paddleTopEdgeY + PADDLE_THICKNESS;
    var paddleLeftEdgeX = paddleX;
    var paddleRightEdgeX = paddleLeftEdgeX + PADDLE_WIDTH;
    if( ballY > paddleTopEdgeY && // below the top of paddle
        ballY < paddleBottomEdgeY && // above bottom of paddle
        ballX > paddleLeftEdgeX && // right of the left side of paddle
        ballX < paddleRightEdgeX) { // left of the left side of paddle

        ballSpeedY *= -1;

        var centerOfPaddleX = paddleX+PADDLE_WIDTH/2;
        var ballDistFromPaddleCenterX = ballX - centerOfPaddleX;
        ballSpeedX = ballDistFromPaddleCenterX * 0.35;

        if(bricksLeft == 0) {
            gameWon = true;
            //brickReset();
        } // out of bricks
    } // ball center inside paddle
} // end of ballPaddleHandling

如果您想查看我的所有代码,可以在此处进行:https://jpst.it/1cHKn

【问题讨论】:

  • 通常我们做的是计算物体(桨)是否在主物体(球)的路径中而不是物体是否与主物体重叠对象。这将问题简化为两条线是否重叠。在您的情况下,您必须考虑桨叶上的 4 条线。
  • ballY += ballSpeedY; 那部分可以让球通过桨。在更换ballY之前,您应该检查是否会发生碰撞。
  • @James 如果球每次移动超过一个桨高度,它可能永远不会“碰撞”(在修改 Y 之前高于桨,之后低于它)
  • @IrkenInvader 对,这就是我的观点。但是在实际移动球之前,很容易检查球是否会穿过球拍。
  • 我认为他们的意思是为球的开始/停止位置和每个桨角开始/停止构建线。 (开始 = 帧前的位置,停止 = 绘制帧后的结束位置)超级有用的糟糕绘图:i.imgur.com/yCzPrww.png

标签: javascript performance collision-detection frame-rate game-loop


【解决方案1】:

也许你的问题是:当你把球放在新位置时,新坐标在桨下,从一帧到另一帧,所以球永远不会通过桨,它只是帧之间的瞬移到桨之后。

也许你需要:计算球的轨迹,当检测到球将在桨Y位置之后,从一帧到另一帧,检查桨是否在中间的轨迹并将球放在桨的上限的新位置

【讨论】:

    【解决方案2】:

    您可以为此使用射线命中测试。 为简化起见,您只需对桨的上表面进行测试。

    function ballPaddleHandling() {
        var paddleTopEdgeY = canvas.height-PADDLE_DIST_FROM_EDGE;
    
        // calculate balls previous position
        var px = ballX - ballSpeedX
        var py = ballY - ballSpeedY
    
        // calculate trajectory angle
        var angle = getAngle(px,py,ballX,ballY) 
    
        // calulcate the length of the ray to test
        var length = getDist(px,py,ballX,ballY)
    
        // define the line to test as the upper face of the paddle
        var line = {x:paddleX, y:paddleTopEdgeY, w:PADDLE_WIDTH}
    
        // get position of hit, or false if no hit occured
        var hit_x = rayHitTestHorizontalLine(px,py,angle,length,line)
    
        if(hit_x!==false){
            ballSpeedY *= -1;
    
            var centerOfPaddleX = paddleX+PADDLE_WIDTH/2;
            var ballDistFromPaddleCenterX = hit_x - centerOfPaddleX;
            ballSpeedX = ballDistFromPaddleCenterX * 0.35;
        }
    }
    
    function rayHitTestHorizontalLine(px,py,angle,length,line){
        var dist = (line.y - py)/(-Math.cos(angle))
        if(dist>length)
            return false
        var hit_x = px+Math.sin(angle)*dist
        if(hit_x>=line.x && hit_x<=line.x+line.w)
            return hit_x
        else
            return false
    }
    
    function getAngle(x1,y1,x2,y2){
        return Math.atan2(y2-y1,x2-x1) + Math.PI/2
    }
    
    function getDist(x1,y1,x2,y2){
        return Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
    }
    

    让我知道它是否有效,我自己无法真正测试它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-06
      相关资源
      最近更新 更多