桨顶部碰撞检测乒乓球

Posted

技术标签:

【中文标题】桨顶部碰撞检测乒乓球【英文标题】:top of paddle collision detection pong 【发布时间】:2013-07-21 01:41:21 【问题描述】:

这是乒乓球的。

我可以得到球和前桨的碰撞,但不是球和桨的顶部,但这段代码似乎是正确的。此代码位于球对象内。球是具有正确宽度和高度属性的方形图像。

    // Paddle collision detection
    // Hits front of paddle
    if ((this.x) == (playerPaddle.x + playerPaddle.width) && (this.y > playerPaddle.y) && this.y < (playerPaddle.y + playerPaddle.height)) 
        console.log("front connect");
        this.vx = -this.vx;
    
    // Hits top of paddle
    if ((this.x + this.width) >= playerPaddle.x && this.x <= (playerPaddle.x + playerPaddle.width) && (this.y + this.height) == playerPaddle.y) 
        console.log("top connect");
        this.vy = -this.vy;
    

如果我将&amp;&amp; (this.y + this.height) == playerPaddle.y) 更改为&amp;&amp; (this.y + this.height) &gt; playerPaddle.y),它就会触发,但显然这是错误的,只要球低于球拍就会触发。这似乎是浏览器中的一个错误,因为它看起来对我来说是正确的。我正在使用 chrome,它似乎总是运行良好。

【问题讨论】:

你能给我们一张照片吗?这很难想象。但是一般来说,一个评论是,如果你正在运行一个框架系统,那么在这些类型的事情中使用 == 是很困难的,因为在一帧中,一个球可以移动超过一个像素,然后你会错过这两件事的那一刻对齐。它应该总是大于/小于。 你为什么要用这么多括号? + 具有更高的优先级 @matty-d 否 ==,现在顶部碰撞可以正常工作,但正面碰撞会同时触发顶部和正面碰撞 if (this.x &lt; playerPaddle.x + playerPaddle.width &amp;&amp; this.x &gt; playerPaddle.x &amp;&amp; this.y &gt; playerPaddle.y &amp;&amp; this.y &lt; playerPaddle.y + playerPaddle.height) console.log("front connect"); this.vx = -this.vx; // Hits top of paddle if (this.x + this.width &gt; playerPaddle.x &amp;&amp; this.x &lt;= playerPaddle.x + playerPaddle.width &amp;&amp; this.y + this.height &gt; playerPaddle.y &amp;&amp; this.y + this.height &lt; playerPaddle.y + playerPaddle.height) console.log("top connect"); this.vy = -this.vy; @matty-d 如果你不确定我的游戏是什么样的,如果你不介意的话,你可以谷歌图片搜索 Atari Pong,谢谢。桨具有顶部和前部、底部和后部表面,球也是如此。它们是矩形的。 如果我们可以使用 ==,我就不必像我发布的代码评论那样写这么长的丑陋 if 语句(这比我的原始代码长得多)。我认为它在撞击前部时会触发前部和顶部碰撞,因为它接触指定为“顶部碰撞”和“前部碰撞”的区域,如果我将前部碰撞区域的球的 x 位置增加 1 个像素,这将得到解决。我只需要建立起重新审视这个复杂代码来尝试它的意志力。 【参考方案1】:

由于二维球是圆形的,因此您需要使用三角函数来正确确定与边缘的连接。我建议您先通过“快速检查”检查一般区域,以防止您的应用变慢。

// Paddle Collision Detection
// Start by a global check to see if the ball is behind the paddle's face
if (this.x <= playerPaddle.x + playerPaddle.width) 
    // Get the ball's radius
    var rad = this.width/2;

    // Give yourself a 3px 'padding' area into the front of the paddle
    // For the detection fo collisions to prevent collision issues caused
    // By a ball moving > 1px in a given frame.  You may want to adjust this number
    var padding = 3;

    // Detect if ball hits front of paddle
    // y collision should be from 1/2 the ball width above the paddle's edge
    // to 1/2 the ball width below the paddle's edge
    if (this.x + padding >= playerPaddle.x + playerPaddle.width 
            && this.y - rad >= playerPaddle.y
            && this.y + rad <= playerPaddle.y + playerPaddle.height) 
        console.log("front connect");
        this.vx = -this.vx;

    // Next, do a "quick check" to see if the ball is in the correct
    // general area for an edge collision prior to doing expensive trig math
     else if (this.y - this.height >= playerPaddle.y
            && this.y <= playerPaddle.y
            && this.x - rad >= playerPaddle.x) 

        // Get the position of the center of the ball
        var x = this.x + rad;
        var y = this.y + rad;

        // Get the position of the corner of the paddle
        var px = playerPaddle.x + playerPaddle.width;
        var py = playerPaddle.y;
        if (this.y + this.height > playerPaddle.y) 
            // if the ball is below the top edge, use the bottom corner
            // of the paddle - else use the top corner of the paddle
            py += playerPaddle.height;
        

        // Do some trig to determine if the ball surface touched the paddle edge
        // Calc the distance (C = sqrt(A^2 + B^2))
        var dist = Math.pow(Math.pow(x - px, 2) + Math.pow(y - py, 2), 0.5);

        // Check if the distance is within the padding zone
        if (dist <= rad && dist >= rad - padding) 
            // Get the angle of contact as Arc-sin of dx/dy
            var angle = Math.asin(x - px / y - py);

            // Adjust the velocity accordingly
            this.vy = (-this.vy * Math.cos(angle)) + (-this.vx * Math.sin(angle));
            this.vx = (-this.vx * Math.cos(angle)) + (-this.vy * Math.sin(angle));
        

    

【讨论】:

谢谢,但我的球是用图像绘制的,它是方形的,我想要那个,因为旧的 Atari Pong 有那个。我已将球的宽度和高度属性设置为与图像相同的像素大小。我可以按照其他人的要求上传图片。我只需要弄清楚如何。我昨天刚加入。 这对我来说太糟糕了!我错过了你提到球是方形的部分问题!不过,我仍然会在此处留下这个答案,因为它可能对尝试使用圆形球的人有所帮助。

以上是关于桨顶部碰撞检测乒乓球的主要内容,如果未能解决你的问题,请参考以下文章

使用旋转矩形进行碰撞检测

使用 Swift 向 UIView 添加碰撞

碰撞检测实现

复杂形状的碰撞检测

复杂形状的碰撞检测

SKPhysicsContact未检测到categoryBitMask碰撞