PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/Samples/Pong/PongGame.cs

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