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