【问题标题】:Ball and brick collision handling球和砖碰撞处理
【发布时间】:2009-10-13 16:56:50
【问题描述】:

我制作了游戏“Breakout”。一个有趣的小项目。

现在,我通常不制作游戏,所以我通常不会考虑碰撞处理。

我有一个桨、一个球和一些积木。

现在,当发生碰撞时(我在提到的每个对象周围绘制矩形),我只需将球的 Y 值更改为 -Y。

这很好用,除非球从侧面(东边或西边)击中砖块。副作用不是很好,会破坏游戏性。

我想我可以放心地假设,当这种情况发生时,我需要将 X 值更改为 -X,而不是上述技术。

到目前为止,我有:if (ballRect.IntersectsWith(brickRect))

ballRectbrickRect 是每个对象周围的矩形。

现在,如果我在砖的东部边界、西部边界等周围创建一个矩形会怎样?我猜宽度大约是一个像素。

如果碰撞发生在西部或东部矩形上,那么球的 X 值应该是 -X。 反之亦然。

那么角落呢?我应该随机选择哪个矩形来控制 x 角吗?

或者我应该在每个角周围画一个矩形?矩形的边长为 1*1。 如果有碰撞 => -x AND -y 球的值?

请分享你的想法。

目前的流程如下:

    foreach (var brick in Bricks)
    {
        if (brick.IsAlive)
        {
            var brickRect = new Rectangle(brick.X, brick.Y, BrickWidth, BrickHeight);
            if (ballRect.IntersectsWith(brickRect)) //Ball has hit brick. lets find out which side of the brick
            {
                var brickRectNorth = new Rectangle(brick.X, brick.Y + BrickHeight, BrickWidth, 1);
                var brickRectSouth = new Rectangle(brick.X, brick.Y, BrickWidth, 1);

                var brickRectEast = new Rectangle(brick.X, brick.Y, 1, BrickHeight);
                var brickRectWest = new Rectangle(brick.X + BrickWidth, brick.Y, 1, BrickHeight);

                if (ballRect.IntersectsWith(brickRectNorth) || ballRect.IntersectsWith(brickRectSouth))
                {
                    //STUFF that makes ball.y = -ball.y
                }
                if (ballRect.IntersectsWith(brickRectWest) || ballRect.IntersectsWith(brickRectEast))
                {
                    //STUFF that makes ball.x = -ball.x
                }
            }
        }
    }

【问题讨论】:

    标签: animation collision-detection


    【解决方案1】:

    与其寻找矩形交点,不如与实际的边缘相交。在拐角处,你的球同时接触了两条边,所以它的运动矢量应该受到两者的影响。

    我会保留单个矩形进行碰撞检测,因为这会减少您需要在外循环中测试的矩形数量,但是一旦检测到与砖块的碰撞,就进入内循环以检测哪个边缘就是被击中了。如果您只是测试每条边并为每条边相应地调整矢量,那么角将免费出现(只要您在找到第一个相交边时不跳出循环)。

    编辑:针对您更新的问题:

    实际上,我就是这样做的(鉴于您的代码,这似乎是 C# 3.0,所以这就是我在下面假设的):

    foreach(var brick in Bricks) {
        if(brick.IsAlive) {
            var brickRect = new Rectangle(brick.X, brick.Y, BrickWidth, BrickHeight);
            if(ballRect.IntersectsWith(brickRect)) {
                // Ball has hit brick.  Now let's adjust the ball's vector accordingly
    
                // Convenience variables.  Compiler will probably inline.
                var brickLeft = brick.X;
                var brickRight = brick.X + BrickWidth;
                var brickTop = brick.Y;
                var brickBottom = brick.Y + BrickHeight;
    
                var ballLeft = ball.X - ball.Radius;
                var ballRight = ball.X + ball.Radius;
                var ballTop = ball.Y - ball.Radius;
                var ballBottom = ball.Y + ball.Radius;
    
                // Test which vector(s) we need to flip
                bool flipX = (ballRight >= brickLeft || ballLeft <= brickRight);
                bool flipY = (ballTop >= brickBottom || ballBottom <= brickTop);
    
                // Flip the vectors (there are probably ways to optimize this,
                // too, but without seeing your code I can't tell).
                if(flipY) {
                    // Stuff that makes ball.y = -ball.y
                }
    
                if(flipX) {
                    // Stuff that makes ball.x = -ball.x
                }
            }
        }
    }
    

    基本上,关键是因为您已经知道球实际上与砖块相交,您可以简化为一个简单的盒子测试,这要快得多。此外,无需为边缘创建额外的矩形 - 只需使用已有矩形的边缘即可。

    【讨论】:

    • 感谢您的反馈。没想到
    • 嗨。球是一个矩形(虽然绘制为日食)。所以半径是:int ballRadius = BallSize/2;关于 //stuff... 我基本上只是做很多事情,比如给玩家 som 点数,杀死砖头等等。最后,它的字面意思是: BallDirection = new Point(-BallDirection.X, BallDirection.Y); //x = -x 你的代码给了我一些非常奇怪的结果,但我会进一步研究它
    猜你喜欢
    • 1970-01-01
    • 2010-09-25
    • 1970-01-01
    • 1970-01-01
    • 2011-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-06
    相关资源
    最近更新 更多