球和砖冲突处理 [英] Ball and brick collision handling

查看:108
本文介绍了球和砖冲突处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经做游戏,突破。一个小的有趣的一面项目。

现在,我通常不会做游戏,所以碰撞的处理是不是我常思考的问题。

我有桨,球和砖块一些。

现在,当有冲突(我周围画提及的每个对象的矩形),我只是改变球的Y值-Y。

这工作正常,但如果球从侧面(无论是东方还是西方)打砖。副作用是不是pretty和废墟游戏的可玩性。

我想我可以放心地假设,而不是上面的技术,我需要改变X值以-X当这种情况发生。

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

ballRect brickRect 周围的每个对象为矩形。

现在,如果我创建了周围的砖,西部边境等东部边界的矩形?我猜的宽度将是约一个像素。

如果碰撞与西方或东方矩形情况,那么球X值应为-X。
反之亦然。

怎么样虽然角落?如果我只是随机选择器x角落其中矩形?

或许我应该让周围的每个角的矩形?矩形为1 * 1在侧。
如果有碰撞=> -x和球-Y价值?

请分享你的看法。

下面是进程迄今:

 的foreach(在砖块VAR砖)
    {
        如果(brick.IsAlive)
        {
            VAR brickRect =新的Rectangle(brick.X,brick.Y,BrickWidth,BrickHeight);
            如果(ballRect.IntersectsWith(brickRect))//球击中砖。让发现砖的哪一侧
            {
                VAR brickRectNorth =新的Rectangle(brick.X,brick.Y + BrickHeight,BrickWidth,1);
                VAR brickRectSouth =新的Rectangle(brick.X,brick.Y,BrickWidth,1);                VAR brickRectEast =新的Rectangle(brick.X,brick.Y,1,BrickHeight);
                VAR brickRectWest =新的Rectangle(brick.X + BrickWidth,brick.Y,1,BrickHeight);                如果(ballRect.IntersectsWith(brickRectNorth)|| ballRect.IntersectsWith(brickRectSouth))
                {
                    //东西,使ball.y = -ball.y
                }
                如果(ballRect.IntersectsWith(brickRectWest)|| ballRect.IntersectsWith(brickRectEast))
                {
                    //东西,使ball.x = -ball.x
                }
            }
        }
    }


解决方案

而不是找矩形十字路口,我会相交的实际边缘。在角落里,你的球是感人的两个边同步,因此它的运动矢量应该由双方的影响。

我会保持碰撞检测单矩形,因为这减少了需要在外环测试矩形的数目,但随后一旦用砖块碰撞已经检测,进入内循环以检测边缘它是被击中。如果只是测试每个边,并相应调整向量为每一个,角落里会免费(只要你不跳出循环,当你找到的第一个交叉边缘)。

修改:在回答你的问题的更新:

事实上,这是我会怎么做(假设你的code,这似乎是C#3.0,所以这就是我下面假设的):

 的foreach(在砖块VAR砖){
    如果(brick.IsAlive){
        VAR brickRect =新的Rectangle(brick.X,brick.Y,BrickWidth,BrickHeight);
        如果(ballRect.IntersectsWith(brickRect)){
            //球击中砖。现在,让我们相应调整球的矢量            //方便变量。编译器可能会内联。
            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;            //测试其载体(S),我们需要翻转
            布尔flipX =(ballRight> = || brickLeft&ballLeft LT = brickRight);
            布尔flipY =(ballTop> = || brickBottom&ballBottom LT = brickTop);            //翻转向量(有可能的方式来优化这个,
            //太多,但没有看到你的code,我不能告诉)。
            如果(flipY){
                //东西,使ball.y = -ball.y
            }            如果(flipX){
                //东西,使ball.x = -ball.x
            }
        }
    }
}

基本上,问题是,既然你已经知道了皮球竟然相交的砖,可以简化为一个简单的框测试,这是要快得多。此外,没有必要为边缘产生额外的矩形 - 只需使用你已经有了矩形的边缘

I have made the game, "Breakout". A small fun side-project.

Now, I usually do not make games, so collision-handling is not something I normally think about.

I have a paddle, a ball and some bricks.

For now, when there is a collision (I draw rectangles around each of the objects mentioned), I simply change the Y value of the ball to -Y.

This works fine, EXCEPT if the ball hits a brick from the side (either East or West). The side-effect is not pretty and ruins the gameplay.

I think I can safely assume that instead of the above technique, I need to change the X value to -X when this happens.

So far I have: if (ballRect.IntersectsWith(brickRect))

ballRect and brickRect being rectangles around each object.

Now, what if I created a rectangle around the eastern border of the brick, the western border, etc? I guess the width would be about a pixel.

If collision happens with western or eastern rectangle, then the balls X value should be -X. And vice versa.

What about the corners though? Should I just randomly choose which rectangle to control of x corner?

Or perhaps should I make a rectangle around each corner? the rectangle being 1*1 in side. If there is a collision => -x AND -y values of the ball?

Please share your thoughts.

Here is the process so far:

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

解决方案

Rather than looking for rectangle intersections, I'd intersect the actual edges. At the corner, your ball is touching two edges simultaneously, so its motion vector should be affected by both.

I would keep the single rectangle for collision detection, since that reduces the number of rectangles you need to test in your outer loop, but then once a collision with a brick has been detected, go into an inner loop to detect which edge it was that was hit. If you just test each edge and adjust the vector accordingly for each one, the corner will come for free (as long as you don't break out of the loop when you find the first intersecting edge).

Edit: In response to your updated question:

Actually, this is how I would do it (given your code, this appears to be C# 3.0, so that's what I've assumed below):

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

Basically, the point is that since you already know the ball actually intersects the brick, you can simplify to a simple box test, which is much faster. Also, there's no need to create extra rectangles for the edges -- just use the edges of the rectangle you already have.

这篇关于球和砖冲突处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆