PageRenderTime 94ms CodeModel.GetById 40ms app.highlight 11ms RepoModel.GetById 39ms app.codeStats 1ms

/Samples/Breakout/BreakoutGame.cs

#
C# | 248 lines | 146 code | 32 blank | 70 comment | 12 complexity | 6991bc6e2c26cac271aef0a4e943b041 MD5 | raw file
  1using System;
  2using System.Collections.Generic;
  3using Delta.Engine.Dynamic;
  4using Delta.Utilities.Datatypes;
  5using Delta.Rendering.Basics.Fonts;
  6using Delta.InputSystem;
  7using Delta.Engine;
  8using Delta.Rendering.Basics.Materials;
  9using Delta.Multimedia;
 10using Delta.Utilities.Helpers;
 11
 12namespace Breakout
 13{
 14	/// <summary>
 15	/// Breakout game
 16	/// </summary>
 17	public class BreakoutGame : DynamicModule
 18	{
 19//TODO: known bug: the collision particle effect is blinking around, there is an issue with the effect system we have to fix soon!
 20//TODO: better and more effects (explosions? ball collision)
 21//TODO: add better trail and when adding trail, we still have to fix geometry and material rendering issues
 22
 23		#region Constants
 24		/// <summary>
 25		/// Name of the command for 'Yes/No' decision of restart the game.
 26		/// </summary>
 27		private const string CommandYesNoClick = "YesNoClick";
 28		/// <summary>
 29		/// Name of the command for quitting the game.
 30		/// </summary>
 31		private const string CommandQuitGame = "Quit";
 32		#endregion
 33
 34		#region Private
 35		/// <summary>
 36		/// The background of the game.
 37		/// </summary>
 38		private Material2D background;
 39
 40		/// <summary>
 41		/// Block material
 42		/// </summary>
 43		private Material2DColored block;
 44
 45		/// <summary>
 46		/// Material to visualize the player paddle.
 47		/// </summary>
 48		private Material2D paddle;
 49
 50		/// <summary>
 51		/// Material to visualize the ball in the game.
 52		/// </summary>
 53		private Material2DColored ball;
 54
 55		/// <summary>
 56		/// The collision sound between the ball and a player paddle.
 57		/// </summary>
 58		private Sound sound;
 59
 60		private List<Point> lastBallPositions;
 61		private Board board;
 62		private int oldScore;
 63
 64		private Rectangle scoreTextArea;
 65		private Rectangle gameOverTextArea;
 66		private Rectangle tryAgainTextArea;
 67		private Rectangle yesTextArea;
 68		private Rectangle noTextArea;
 69		#endregion
 70
 71		#region Constructor
 72		/// <summary>
 73		/// Create breakout game
 74		/// </summary>
 75		public BreakoutGame()
 76			: base(typeof(BreakoutGame).Name, typeof(IGraphic))
 77		{
 78			// Load all needed content
 79			background = new Material2D("SpaceBackground");
 80			block = new Material2DColored("BreakoutBlock");
 81
 82			paddle = new Material2D("Paddle");
 83			ball = new Material2DColored("Ball");
 84			sound = new Sound("DefaultSound");
 85			//disabled: music = new Music("DefaultMusic");
 86
 87			lastBallPositions = new List<Point>();
 88			board = new Board();
 89			Settings.Extra.LimitFramerateNumber = 60;
 90			oldScore = MathHelper.InvalidIndex;
 91
 92			scoreTextArea = Rectangle.FromCenter(0.5f, 0.6f, 0.25f, 0.05f);
 93			gameOverTextArea = Rectangle.FromCenter(0.5f, 0.25f, 0.15f, 0.05f);
 94			tryAgainTextArea = Rectangle.FromCenter(0.5f, 0.4f, 0.15f, 0.05f);
 95			yesTextArea = Rectangle.FromCenter(0.25f, 0.75f, 0.1f, 0.05f);
 96			noTextArea = Rectangle.FromCenter(0.75f, 0.75f, 0.1f, 0.05f);
 97
 98			RegisterInputCommands();
 99		}
100		#endregion
101
102		#region RegisterInputCommands
103		/// <summary>
104		/// Register input commands
105		/// </summary>
106		private void RegisterInputCommands()
107		{
108			// Restart game
109			Input.Commands[CommandYesNoClick].Add(this,
110				delegate(CommandTrigger trigger)
111				{
112					// Check if the player wants to replay
113					if (yesTextArea.Contains(trigger.Position))
114					{
115						sound.Play();
116						board.StartGame();
117						board.GameOver = false;
118					}
119
120					// or just quit the game now
121					if (noTextArea.Contains(trigger.Position))
122					{
123						sound.Play();
124						Application.Quit();
125					}
126				});
127
128			// Quit game
129			Input.Commands[CommandQuitGame].Add(this, delegate
130			{
131				Application.Quit();
132			});
133		}
134		#endregion
135
136		#region Run (override)
137		/// <summary>
138		/// Run
139		/// </summary>
140		public override void Run()
141		{
142			// Render background (resolution independent)
143			background.Draw(Rectangle.One);
144
145			Font textFont = Font.Default;
146
147			if (board.GameOver)
148			{
149				#region Game over menu
150				textFont.Draw("Game over", gameOverTextArea);
151				textFont.Draw("Try again?", tryAgainTextArea);
152
153				textFont.Draw("Score: " + board.Score, scoreTextArea);
154
155				textFont.Draw("Yes", yesTextArea);
156				textFont.Draw("No", noTextArea);
157				#endregion
158			}
159			else
160			{
161				Rectangle drawArea = ScreenSpace.DrawArea;
162
163				#region Ingame
164				board.UpdateGame();
165				// Use the score to detect if we had some collision
166				if (oldScore != board.Score)
167				{
168					// Initialization?
169					if (oldScore == MathHelper.InvalidIndex)
170					{
171						//disabled: music.Looping = true;
172						//disabled: music.Play();
173					}
174
175					// If this was just a paddle collision (1 score), use less volume
176					sound.Volume = (board.Score == oldScore + 1) ? 0.5f : 1.0f;
177					sound.Play();
178
179					oldScore = board.Score;
180				}
181
182				// Render all blocks with their color
183				for (int x = 0; x < board.Level; x++)
184				{
185					for (int y = 0; y < board.Level; y++)
186					{
187						Brick brick = board.Bricks[x, y];
188
189						if (brick.IsDead == false)
190						{
191							block.BlendColor = brick.Color;
192							block.Draw(drawArea.GetInnerRectangle(brick.Bounds));
193						} // if
194					} // for
195				} // for
196
197				// Remaining Lives text rendering
198				string livesString = "Lives: " + board.Lives;
199				Size livesStringSize = textFont.Measure(livesString);
200				textFont.Draw(livesString, new Rectangle(drawArea.BottomLeft +
201					new Point(0.005f, -livesStringSize.Height), livesStringSize));
202
203				// Scores Rendering
204				string scoreString = "Score: " + board.Score;
205				Size scoreStringSize = textFont.Measure(scoreString);
206				textFont.Draw(scoreString, new Rectangle(drawArea.BottomRight -
207					scoreStringSize - new Point(0.005f, 0.0f), scoreStringSize));
208
209				// And finally the bonus for each hit in the middle
210				textFont.Draw("Bonus: " + board.DestroyedBlocks,
211					new Rectangle(0.0f, drawArea.Bottom - textFont.LineHeight, 1.0f,
212						textFont.LineHeight));
213
214				// Render the paddle itself
215				Size ballSize = new Size(board.Ball.Radius, board.Ball.Radius);
216				paddle.Draw(drawArea.GetInnerRectangle(
217					new Rectangle(board.PlayerPaddle.Position -
218						new Size(board.PlayerPaddle.Size.WidthHalf,
219						-ballSize.Height * 0.5f),
220						board.PlayerPaddle.Size)));
221
222				// And finally draw the animated ball with trail
223				//TODO: add better trail (maybe as effect)
224				//if (lastBallPositions.Count > 10)
225				//{
226				//  // Remove first if we have more than 10 ball trail positions
227				//  lastBallPositions.RemoveAt(0);
228				//}
229				//lastBallPositions.Add(board.Ball.Position);
230				//// Draw all trails (0-9, in the first frames we will have less)
231				//for (int num = 0; num < lastBallPositions.Count; num++)
232				//{
233				Rectangle ballRect = drawArea.GetInnerRectangle(
234					//new Rectangle(lastBallPositions[num] - ballSize,
235					new Rectangle(board.Ball.Position - ballSize, ballSize * 2));
236				// Set size back to quadratic space for the correct aspect ratio
237				//float trailAlpha = (num + 1) / 10.0f;
238				ballRect.Size = ballSize * 2;// * trailAlpha;
239				//ballRect.Position -= ballSize * 2 * trailAlpha / 2.0f;
240				//ball.BlendColor = new Color(Color.White, trailAlpha);
241				ball.Draw(ballRect);
242				//}
243				#endregion
244			}
245		}
246		#endregion
247	}
248}