/* * $RCSfile$ * Copyright (C) 2006 Rob Loach (http://www.robloach.net) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections.Generic; using System.IO; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Components; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; namespace BrickBust { /// /// This is the main type for your game /// partial class BrickBustGame : Microsoft.Xna.Framework.Game { const float PaddleSpeed = 120f; const float BallStartSpeed = 60f; public BrickBustGame() { InitializeComponent(); } protected override void OnStarting() { // Load game resources and setup graphic device events graphics.DeviceReset += new EventHandler(graphics_DeviceReset); LoadResources(); // Setup the game m_Paddle.X = graphics.BackBufferWidth / 2f - m_Textures["Paddle"].Width / 2f; m_Paddle.Y = graphics.BackBufferHeight - m_Textures["Paddle"].Height * 2f; ResetGame(); } void graphics_DeviceReset(object sender, EventArgs e) { // Reload the resources if the graphics device is lost LoadResources(); } private void LoadResources() { // Load textures and initialize sprite drawing m_Sprite = new SpriteBatch(graphics.GraphicsDevice); m_Textures["Bricks"] = Texture2D.FromFile(graphics.GraphicsDevice, Path.Combine("Graphics", "Bricks.png")); m_Textures["Paddle"] = Texture2D.FromFile(graphics.GraphicsDevice, Path.Combine("Graphics", "Paddle.png")); m_Textures["Ball"] = Texture2D.FromFile(graphics.GraphicsDevice, Path.Combine("Graphics", "Ball.png")); } protected override void Update() { // The time since Update was called last float elapsed = (float)ElapsedTime.TotalSeconds; // TODO: Add your game logic here // Check player input KeyboardState keyboard = Keyboard.GetState(); if (keyboard.IsKeyDown(Keys.Left)) m_Paddle.X -= PaddleSpeed * elapsed; else if(keyboard.IsKeyDown(Keys.Right)) m_Paddle.X += PaddleSpeed * elapsed; // Bound paddle in the game screen if (m_Paddle.X < 0) m_Paddle.X = 0f; else if (m_Paddle.X + m_Textures["Paddle"].Width > graphics.BackBufferWidth) m_Paddle.X = graphics.BackBufferWidth - m_Textures["Paddle"].Width; // Move the ball m_Ball.X += m_BallSpeed.X * elapsed; m_Ball.Y += m_BallSpeed.Y * elapsed; // Check ball collisions with walls if (m_Ball.X < 0f && m_BallSpeed.X < 0f) m_BallSpeed.X *= -1f; if (m_Ball.X + m_Textures["Ball"].Width > graphics.BackBufferWidth && m_BallSpeed.X > 0f) m_BallSpeed.X *= -1f; if (m_Ball.Y < 0f && m_BallSpeed.Y < 0f) m_BallSpeed.Y *= -1f; if (m_Ball.Y > graphics.BackBufferHeight) { m_BallsLeft--; ResetBall(); if (m_BallsLeft <= 0) ResetGame(); } // Check ball collisions with bricks float brickWidth = m_Textures["Bricks"].Width / 3f; float brickHeight = m_Textures["Bricks"].Height / 3f; float ballWidth = m_Textures["Ball"].Width; float ballHeight = m_Textures["Ball"].Height; for (int x = 0; x < m_CurrentLevel.Blocks.GetLength(1); x++) { for (int y = 0; y < m_CurrentLevel.Blocks.GetLength(0); y++) { if (m_CurrentLevel.Blocks[y, x] > 0) { float brickX = x * brickWidth; float brickY = y * brickHeight; bool hit = false; // Check if hit top if (IsPointInRectangle(m_Ball.X + ballWidth / 2f, m_Ball.Y, brickX, brickY, brickWidth, brickHeight)) { hit = true; m_BallSpeed.Y *= -1f; m_Ball.Y = brickY + brickHeight; } // Check if hit bottom else if (IsPointInRectangle(m_Ball.X + ballWidth / 2f, m_Ball.Y + ballHeight, brickX, brickY, brickWidth, brickHeight)) { hit = true; m_BallSpeed.Y *= -1f; m_Ball.Y = brickY - ballHeight; } // Check if hit left if (IsPointInRectangle(m_Ball.X, m_Ball.Y + ballHeight / 2f, brickX, brickY, brickWidth, brickHeight)) { hit = true; m_BallSpeed.X *= -1f; m_Ball.X = brickX + brickWidth; } // Check if hit right else if (IsPointInRectangle(m_Ball.X + ballWidth, m_Ball.Y + ballHeight / 2f, brickX, brickY, brickWidth, brickHeight)) { hit = true; m_BallSpeed.X *= -1f; m_Ball.X = brickX - ballWidth; } if (hit && m_CurrentLevel.Blocks[y, x] != 9) { // Decrease the life of the brick and increase the player's score m_Score += m_CurrentLevel.Blocks[y, x]--; // Check winning conditions if (m_CurrentLevel.Blocks[y, x] <= 0) CheckIfWon(); } } } } // Check ball collision with paddle if (m_BallSpeed.Y > 0f) { if (m_Ball.Y + ballHeight > m_Paddle.Y && m_Ball.Y < m_Paddle.Y + m_Textures["Paddle"].Height && m_Ball.X < m_Paddle.X + m_Textures["Paddle"].Width && m_Ball.X + ballWidth > m_Paddle.X) { // Reverse Y direction while increasing speed m_BallSpeed.Y *= -1.05f; // Check if the player is going to change direction of ball if (keyboard.IsKeyDown(Keys.Left)) m_BallSpeed.X = -Math.Abs(m_BallSpeed.X) - BallStartSpeed / 4f; else if(keyboard.IsKeyDown(Keys.Right)) m_BallSpeed.X = Math.Abs(m_BallSpeed.X) + BallStartSpeed / 4f; } } // Let the GameComponents update UpdateComponents(); } public void CheckIfWon() { // Go through each block and see if the player won bool won = true; foreach (int i in m_CurrentLevel.Blocks) { if (i > 0 && i < 9) { won = false; break; } } if (won) { m_CurrentLevel = new Level(++m_Level); ResetBall(); } } bool IsPointInRectangle(float x, float y, float rectX, float rectY, float rectWidth, float rectHeight) { // Return true if the point is in the rectangle if ((x >= rectX) && (x <= rectX + rectWidth) && (y >= rectY) && (y <= rectY + rectHeight)) return true; return false; } protected override void Draw() { // Make sure we have a valid device if (!graphics.EnsureDevice()) return; graphics.GraphicsDevice.Clear(Color.Black); graphics.GraphicsDevice.BeginScene(); // TODO: Add your drawing code here // Prepare to draw all game entities m_Sprite.Begin(SpriteBlendMode.AlphaBlend); // Draw all bricks int width = m_Textures["Bricks"].Width / 3; int height = m_Textures["Bricks"].Height / 3; for (int x = 0; x < m_CurrentLevel.Blocks.GetLength(1); x++) { for (int y = 0; y < m_CurrentLevel.Blocks.GetLength(0); y++) { // Base the brick colour on how much life is left in the ball Rectangle source = Rectangle.Empty; switch (m_CurrentLevel.Blocks[y, x]) { case 1: source = new Rectangle(0, 0, width, height); break; case 2: source = new Rectangle(width, 0, width, height); break; case 3: source = new Rectangle(width * 2, 0, width, height); break; case 4: source = new Rectangle(0, height, width, height); break; case 5: source = new Rectangle(width, height, width, height); break; case 6: source = new Rectangle(width * 2, height, width, height); break; case 7: source = new Rectangle(0, height * 2, width, height); break; case 8: source = new Rectangle(width, height * 2, width, height); break; case 9: source = new Rectangle(width * 2, height * 2, width, height); break; } if (source != Rectangle.Empty) m_Sprite.Draw(m_Textures["Bricks"], new Vector2(x * width, y * height), source, Color.White); } } // Draw the paddle and the ball m_Sprite.Draw(m_Textures["Ball"], m_Ball, Color.White); m_Sprite.Draw(m_Textures["Paddle"], m_Paddle, Color.White); m_Sprite.End(); // Display the textual data to the player using our fancy BitmapFont object smallFont.Draw(10f, 5f, "Score: " + m_Score); smallFont.Draw(graphics.BackBufferWidth - 10f, 5f, "Level: " + m_Level, BitmapFont.Alignment.Right); smallFont.Draw(graphics.BackBufferWidth / 2f, 5f, "Balls: " + m_BallsLeft, BitmapFont.Alignment.Center); // Let the GameComponents draw DrawComponents(); graphics.GraphicsDevice.EndScene(); graphics.GraphicsDevice.Present(); } public void ResetGame() { // Restart the whole game m_Score = 0; m_BallsLeft = 5; m_CurrentLevel = new Level(m_Level = 1); ResetBall(); } public void ResetBall() { // Reset the position and speed of the ball m_Ball.X = m_Paddle.X + m_Textures["Paddle"].Width / 2f - m_Textures["Ball"].Width / 2f; m_Ball.Y = m_Paddle.Y; m_BallSpeed = new Vector2(BallStartSpeed, -BallStartSpeed); } #region Fields private SpriteBatch m_Sprite; private int m_Score = 0; private int m_Level = 1; private int m_BallsLeft = 5; private Level m_CurrentLevel = new Level(1); private Vector2 m_Paddle = new Vector2(); private Vector2 m_Ball = new Vector2(); private Vector2 m_BallSpeed = new Vector2(BallStartSpeed, -BallStartSpeed); private Dictionary m_Textures = new Dictionary(); #endregion Fields } }