Esempio n. 1
0
 private void CheckBallBricksCollision(Ball ball, GameTime gameTime)
 {
     for (int i = 0; i < bricks.Length; i++)
     {
         for (int j = 0; j < bricks[i].Length; j++)
         {
             if (bricks[i][j] != null && IsOpenForHit(i, j))
             {
                 if (!bricks[i][j].IsDestroyed)
                 {
                     Brick brick = bricks[i][j];
                     CollisionResolutionInfo collisionInfo = CollisionUtils.CheckCollision(gameTime.ElapsedGameTime.Milliseconds, ball, brick);
                     if (collisionInfo != null)
                     {
                         HitBrick(i, j, ball.IsFlaming, bricks[i][j].IsDetonating, 0);
                         ball.Velocity      = collisionInfo.BallVelocity;
                         ball.DrawRectangle = collisionInfo.BallDrawRectangle;
                     }
                 }
             }
         }
     }
 }
        /// <summary>
        /// Finds a moment of ball-brick collision.
        /// Change position and velocity of the ball after collision.
        /// </summary>
        /// <param name="timeStep">The time step.</param>
        /// <param name="ball">The ball.</param>
        /// <param name="brick">The brick.</param>
        /// <returns>The collision resolution info object.</returns>
        public static CollisionResolutionInfo CheckCollision(int timeStep, Ball ball, Brick brick)
        {
            BoundingBallRect initialBallRect = new BoundingBallRect();
            BoundingBallRect currentBallRect = new BoundingBallRect();

            if (ball.CollisionRectangle.Intersects(brick.CollisionRectangle))
            {
                if (!ball.IsFlaming)
                {
                    // initialize non-changing properties
                    currentBallRect.drawRectangle.Width  = ball.DrawRectangle.Width;
                    currentBallRect.drawRectangle.Height = ball.DrawRectangle.Height;

                    currentBallRect.collisionRectangle = ball.CollisionRectangle;

                    // back up ball to it's location before the time step
                    float dX = (ball.Velocity.X * timeStep);
                    float dY = (ball.Velocity.Y * timeStep);
                    initialBallRect.drawRectangle.X      = ball.DrawRectangle.X - (int)dX;
                    initialBallRect.drawRectangle.Y      = ball.DrawRectangle.Y - (int)dY;
                    initialBallRect.drawRectangle.Width  = ball.DrawRectangle.Width;
                    initialBallRect.drawRectangle.Height = ball.DrawRectangle.Height;
                    initialBallRect.collisionRectangle.X = ball.CollisionRectangle.X - (int)dX;
                    initialBallRect.collisionRectangle.Y = ball.CollisionRectangle.Y - (int)dY;

                    // find a moment of the ball-brick collision
                    // at fixed time step of 60 fps, time increment can only be 8, 4, 2, or 1
                    int timeIncrement = timeStep / 2;
                    int collisionDt   = timeStep;  // we know we have a collision or we wouldn't be here
                    int dt            = timeIncrement;
                    while (timeIncrement > 0)
                    {
                        // move ball forward by dt from its initial position
                        dX = ball.Velocity.X * dt;
                        dY = ball.Velocity.Y * dt;

                        // update ball bounding rectangle
                        currentBallRect.drawRectangle.X      = initialBallRect.drawRectangle.X + (int)dX;
                        currentBallRect.drawRectangle.Y      = initialBallRect.drawRectangle.Y + (int)dY;
                        currentBallRect.collisionRectangle.X = initialBallRect.collisionRectangle.X + (int)dX;
                        currentBallRect.collisionRectangle.Y = initialBallRect.collisionRectangle.Y + (int)dY;

                        // cut time increment in half as we search for the time of collision
                        timeIncrement /= 2;

                        if (currentBallRect.collisionRectangle.Intersects(brick.CollisionRectangle))
                        {
                            // collision detected, so save collision dt and reduce dt to make it earlier
                            collisionDt = dt;
                            dt         -= timeIncrement;
                        }
                        else
                        {
                            // no collision detected, so increase dt to make it later
                            dt += timeIncrement;
                        }
                    }

                    // get rectangle location at start of collision
                    int collisionStartTime = collisionDt;
                    dX = ball.Velocity.X * collisionStartTime;
                    dY = ball.Velocity.Y * collisionStartTime;

                    currentBallRect.drawRectangle.X      = initialBallRect.drawRectangle.X + (int)dX;
                    currentBallRect.drawRectangle.Y      = initialBallRect.drawRectangle.Y + (int)dY;
                    currentBallRect.collisionRectangle.X = initialBallRect.collisionRectangle.X + (int)dX;
                    currentBallRect.collisionRectangle.Y = initialBallRect.collisionRectangle.Y + (int)dY;

                    // find the area where ball overlaps brick
                    Rectangle     intersectionArea = Rectangle.Intersect(currentBallRect.collisionRectangle, brick.CollisionRectangle);
                    CollisionSide collisionSide    = GetCollisionSide(currentBallRect.collisionRectangle,
                                                                      intersectionArea, ball.Velocity);

                    // move objects through complete time step
                    int preCollisionDuration    = collisionStartTime - 1;
                    int postCollisionDuration   = timeStep - collisionStartTime + 1;
                    CollisionResolutionInfo cri = BounceBall(ball.Velocity, initialBallRect.drawRectangle,
                                                             preCollisionDuration, postCollisionDuration,
                                                             collisionSide);

                    return(cri);
                }
                else
                {
                    return(new CollisionResolutionInfo(ball.Velocity, ball.DrawRectangle));
                }
            }
            else
            {
                // no collision
                return(null);
            }
        }