PageRenderTime 84ms CodeModel.GetById 40ms app.highlight 14ms RepoModel.GetById 26ms app.codeStats 0ms

/Samples/Pong/PongGame.cs

#
C# | 378 lines | 235 code | 39 blank | 104 comment | 10 complexity | a8f8a73cb0f1d60d085d3d5dcc9ec80a MD5 | raw file
  1using System;
  2using Delta.Engine.Dynamic;
  3using Delta.Engine.SettingsNodes;
  4using Delta.Utilities.Datatypes;
  5using Delta.Engine;
  6using Delta.Rendering.Basics.Materials;
  7using Delta.Multimedia;
  8using Delta.Utilities.Helpers;
  9using Delta.InputSystem;
 10using Delta.Rendering.Basics.Fonts;
 11using Delta.Rendering.Basics.Drawing;
 12using Delta.Utilities.Datatypes.Advanced;
 13
 14namespace Pong
 15{
 16	/// <summary>
 17	/// Pong game
 18	/// </summary>
 19	public class PongGame : DynamicModule
 20	{
 21		#region Constants
 22		/// <summary>
 23		/// Name of the MoveUp command for player one.
 24		/// </summary>
 25		private const string PlayerOneMoveUpDigital = "PlayerOneMoveUpDigital";
 26		/// <summary>
 27		/// Name of the MoveDown command for player one.
 28		/// </summary>
 29		private const string PlayerOneMoveDownDigital = "PlayerOneMoveDownDigital";
 30		/// <summary>
 31		/// Name of the MoveUp command for player two per keyboard or digital
 32		/// GamePad.
 33		/// </summary>
 34		private const string PlayerTwoMoveUpDigital = "PlayerTwoMoveUpDigital";
 35		/// <summary>
 36		/// Name of the MoveDown command for player two per keyboard or digital
 37		/// GamePad.
 38		/// </summary>
 39		private const string PlayerTwoMoveDownDigital = "PlayerTwoMoveDownDigital";
 40		/// <summary>
 41		/// Name of the MoveUp command for player two per mouse or touch.
 42		/// </summary>
 43		private const string PlayerTwoMoveDirect = "PlayerTwoMoveDirect";
 44		/// <summary>
 45		/// Name of the command for quitting the game.
 46		/// </summary>
 47		private const string CommandQuitGame = "Quit";
 48		#endregion
 49
 50		#region Private
 51		#region DrawArea
 52		/// <summary>
 53		/// Draw area of the screen in Quadratic Space
 54		/// </summary>
 55		private Rectangle DrawArea
 56		{
 57			get
 58			{
 59				return ScreenSpace.DrawArea;
 60			} // get
 61		}
 62		#endregion
 63
 64		#region PaddleSpeed
 65		/// <summary>
 66		/// The speed of the paddle if it will be moved by a digital input device
 67		/// (Keyboard or GamePad)
 68		/// </summary>
 69		private float PaddleSpeed
 70		{
 71			get
 72			{
 73				return 0.75f * Time.Delta;
 74			}
 75		}
 76
 77		/// <summary>
 78		/// AI speed, much slower ^^
 79		/// </summary>
 80		private float AISpeed
 81		{
 82			get
 83			{
 84				return 0.2f * Time.Delta;
 85			}
 86		}
 87		#endregion
 88
 89		/// <summary>
 90		/// The background of the game.
 91		/// </summary>
 92		private Material2D background;
 93
 94		/// <summary>
 95		/// Material to visualize the left player paddle.
 96		/// </summary>
 97		private Material2DColored leftPaddle;
 98		/// <summary>
 99		/// Material to visualize the right player paddle.
100		/// </summary>
101		private Material2DColored rightPaddle;
102
103		#region HalfPaddleSize
104		/// <summary>
105		/// Half paddle size
106		/// </summary>
107		private Size HalfPaddleSize
108		{
109			get
110			{
111				return leftPaddle.Size * 0.5f;
112			} // get
113		}
114		#endregion
115
116		/// <summary>
117		/// Center position of the left player paddle.
118		/// </summary>
119		private Point player1Position;
120		/// <summary>
121		/// Center position of the right player paddle.
122		/// </summary>
123		private Point player2Position;
124
125		/// <summary>
126		/// Current score of the left player.
127		/// </summary>
128		private int player1Score = 0;
129		/// <summary>
130		/// Current score of the right player.
131		/// </summary>
132		private int player2Score = 0;
133
134		/// <summary>
135		/// Initially player 1 (left paddle) is controlled by the AI until you press
136		/// a command/ trigger button for player 2 (then it will only be controlled
137		/// by a human).
138		/// </summary>
139		private bool isPlayer1AI = true;
140
141		/// <summary>
142		/// Material to visualize the ball in the game.
143		/// </summary>
144		private Material2DColored ball;
145
146		#region HalfBallSize
147		/// <summary>
148		/// Half ball size
149		/// </summary>
150		private Size HalfBallSize
151		{
152			get
153			{
154				return ball.Size * 0.5f;
155			} // get
156		}
157		#endregion
158
159		#region BallRadius
160		/// <summary>
161		/// Ball radius
162		/// </summary>
163		private float BallRadius
164		{
165			get
166			{
167				return HalfBallSize.Width;
168			} // get
169		}
170		#endregion
171
172		/// <summary>
173		/// The current position of the ball.
174		/// </summary>
175		private Point ballPosition;
176		/// <summary>
177		/// The current velocity of the ball.
178		/// </summary>
179		private Point ballVelocity;
180
181		/// <summary>
182		/// The collision sound between the ball and a player paddle.
183		/// </summary>
184		private Sound sound;
185		#endregion
186
187		#region Constructor
188		/// <summary>
189		/// Create pong game
190		/// </summary>
191		public PongGame()
192			: base("PongGame", typeof(IGraphic))
193		{
194			// Initialize game elements
195			background = new Material2D("SpaceBackground");
196
197			leftPaddle = new Material2DColored("PongPaddle")
198			{
199				BlendColor = Color.Red,
200			};
201			rightPaddle = new Material2DColored("PongPaddle")
202			{
203				BlendColor = Color.Green,
204			};
205
206			ball = new Material2DColored("Ball");
207			ballPosition = Point.Half;
208			ballVelocity = new Point(0.3f, RandomHelper.RandomFloat(-0.2f, 0.2f));
209
210			player1Position = new Point(DrawArea.Left + 0.05f, DrawArea.Top + 0.1f);
211			player2Position = new Point(DrawArea.Right - 0.05f,
212				DrawArea.Bottom - 0.1f);
213
214			sound = new Sound("DefaultSound");
215
216			RegisterInputCommands();
217		}
218		#endregion
219
220		#region RegisterInputCommands
221		/// <summary>
222		/// Register input commands
223		/// </summary>
224		private void RegisterInputCommands()
225		{
226			// Player One paddle movement (up and down)
227			Input.Commands[PlayerOneMoveUpDigital].Add(this, delegate
228			{
229				player1Position.Y -= PaddleSpeed;
230				isPlayer1AI = false;
231			});
232			Input.Commands[PlayerOneMoveDownDigital].Add(this, delegate
233			{
234				player1Position.Y += PaddleSpeed;
235				isPlayer1AI = false;
236			});
237
238			// Player two paddle movement (up and down)
239			Input.Commands[PlayerTwoMoveUpDigital].Add(this, delegate
240			{
241				player2Position.Y -= PaddleSpeed;
242			});
243			Input.Commands[PlayerTwoMoveDownDigital].Add(this, delegate
244			{
245				player2Position.Y += PaddleSpeed;
246			});
247
248			// Direct move control via mouse or touch (just for player 2)
249			Input.Commands[PlayerTwoMoveDirect].Add(this,
250				delegate(CommandTrigger trigger)
251			{
252				player2Position.Y = trigger.Position.Y;
253			});
254
255			// Quit game with Escape, Back or Alt+F4
256			Input.Commands[CommandQuitGame].Add(this, delegate
257			{
258				Application.Quit();
259			});
260		}
261		#endregion
262
263		#region Run (override)
264		/// <summary>
265		/// Run
266		/// </summary>
267		public override void Run()
268		{
269			Rectangle drawArea = ScreenSpace.DrawArea;
270
271			#region AI
272			if (isPlayer1AI)
273			{
274				// The AI does an ridiculously easy thing, it just follows the ball!
275				if (player1Position.Y > ballPosition.Y - AISpeed)
276				{
277					player1Position.Y -= AISpeed;
278				}
279				else if (player1Position.Y < ballPosition.Y + AISpeed)
280				{
281					player1Position.Y += AISpeed;
282				}
283			}
284			#endregion
285
286			#region Ball physics
287			//float deltaTime = Time.Delta > 0.7f ? 0.1f : Time.Delta;
288			// Move the ball.
289			ballPosition += ballVelocity * Time.Delta;
290
291			// Make the ball faster over time.
292			ballVelocity *= 1f + (0.07f * Time.Delta);
293
294			// Floor and ceiling collision
295			if ((ballPosition.Y <= drawArea.Top + BallRadius &&
296					ballVelocity.Y < 0f) ||
297				(ballPosition.Y >= drawArea.Bottom - BallRadius &&
298					ballVelocity.Y > 0f))
299			{
300				ballVelocity.Y = -ballVelocity.Y;
301			}
302
303			// Paddle collision
304			Rectangle ballCollisionRect = Rectangle.FromCenter(ballPosition,
305				// Reduce ball size a bit to make collisions less unnatural at borders
306				ball.Size * 0.75f);
307
308			// Clamp the paddle to the screen area so it don't will run out of the
309			// screen
310			player1Position.Y = MathHelper.Clamp(player1Position.Y,
311				drawArea.Top + 0.05f, drawArea.Bottom - 0.05f);
312			player2Position.Y = MathHelper.Clamp(player2Position.Y,
313				drawArea.Top + 0.05f, drawArea.Bottom - 0.05f);
314
315			Rectangle paddle1Area = new Rectangle(
316				player1Position - HalfPaddleSize, leftPaddle.Size);
317			Rectangle paddle2Area = new Rectangle(
318				player2Position - HalfPaddleSize, rightPaddle.Size);
319
320			if (paddle1Area.Contains(ballCollisionRect) >= ContainmentType.Partial &&
321				ballVelocity.X < 0f)
322			{
323				sound.Play();
324				ballVelocity.X = -ballVelocity.X;
325			} // if
326			if (paddle2Area.Contains(ballCollisionRect) >= ContainmentType.Partial &&
327				ballVelocity.X > 0f)
328			{
329				sound.Play();
330				ballVelocity.X = -ballVelocity.X;
331			} // if
332
333			// Goal collision
334			if (ballPosition.X <= drawArea.Left)
335			{
336				player2Score++;
337				ballPosition = Point.Half;
338				ballVelocity = new Point(0.3f,
339					RandomHelper.RandomFloat(-0.2f, 0.2f));
340			} // if
341			if (ballPosition.X >= drawArea.Right)
342			{
343				player1Score++;
344				ballPosition = Point.Half;
345				ballVelocity = new Point(-0.3f,
346					RandomHelper.RandomFloat(-0.2f, 0.2f));
347			} // if
348
349			if (Settings.Debug.IsDrawDebugInfoModeOn(ProfilingMode.Custom))
350			{
351				Rect.DrawOutline(paddle1Area, Color.Blue);
352				Rect.DrawOutline(paddle2Area, Color.Blue);
353				Circle.DrawOutline(ballPosition, BallRadius, Color.Yellow);
354				Rect.DrawOutline(ballCollisionRect, Color.Yellow);
355			}
356			#endregion
357
358			#region Drawing
359			background.Draw(drawArea);
360			
361			leftPaddle.Draw(paddle1Area, 180);
362			rightPaddle.Draw(paddle2Area);
363			Rectangle ballArea = new Rectangle(ballPosition - HalfBallSize,
364				ball.Size);
365			ball.Draw(ballArea, Time.Milliseconds / 5.0f);
366
367			Font textFont = Font.Default;
368			textFont.Draw(player1Score + " | SCORE | " + player2Score,
369				new Rectangle(0.0f, drawArea.Top, 1.0f, textFont.LineHeight));
370			textFont.Draw(
371				"Controls: W/S (left player), Cursor keys/GamePad (right player)",
372				new Rectangle(0.0f, drawArea.Top + textFont.LineHeight, 1.0f,
373					textFont.LineHeight));
374			#endregion
375		}
376		#endregion
377	}
378}