PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Samples/Breakout/Ball.cs

#
C# | 185 lines | 159 code | 23 blank | 3 comment | 16 complexity | 0d4fd53dc453678f49f343eb073a5a91 MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using DeltaEngine.Commands;
  4. using DeltaEngine.Content;
  5. using DeltaEngine.Core;
  6. using DeltaEngine.Datatypes;
  7. using DeltaEngine.Entities;
  8. using DeltaEngine.Extensions;
  9. using DeltaEngine.Input;
  10. using DeltaEngine.Multimedia;
  11. using DeltaEngine.Rendering2D;
  12. namespace Breakout
  13. {
  14. /// <summary>
  15. /// The player interacts with the ball with his paddle and navigates it to destroy bricks.
  16. /// </summary>
  17. public class Ball : Sprite
  18. {
  19. public Ball(Paddle paddle)
  20. : base(new Material(ShaderFlags.Position2DColoredTextured,"Ball"), Rectangle.Zero)
  21. {
  22. this.paddle = paddle;
  23. fireBallSound = ContentLoader.Load<Sound>("PaddleBallStart");
  24. collisionSound = ContentLoader.Load<Sound>("BallCollision");
  25. UpdateOnPaddle();
  26. RegisterFireBallCommand();
  27. Start<RunBall>();
  28. RenderLayer = 5;
  29. }
  30. private readonly Paddle paddle;
  31. private readonly Sound fireBallSound;
  32. private readonly Sound collisionSound;
  33. private void UpdateOnPaddle()
  34. {
  35. isOnPaddle = true;
  36. Position = new Vector2D(paddle.Position.X, paddle.Position.Y - Radius);
  37. }
  38. protected bool isOnPaddle;
  39. private void RegisterFireBallCommand()
  40. {
  41. var command = new Command(FireBallFromPaddle);
  42. command.Add(new KeyTrigger(Key.Space));
  43. command.Add(new MouseButtonTrigger());
  44. command.Add(new GamePadButtonTrigger(GamePadButton.A));
  45. }
  46. private void FireBallFromPaddle()
  47. {
  48. if (!isOnPaddle || !IsVisible)
  49. return;
  50. isOnPaddle = false;
  51. float randomXSpeed = Randomizer.Current.Get(-0.15f, 0.15f);
  52. velocity = new Vector2D(randomXSpeed.Abs() < 0.01f ? 0.01f : randomXSpeed, StartBallSpeedY);
  53. fireBallSound.Play();
  54. }
  55. protected static Vector2D velocity;
  56. private const float StartBallSpeedY = -1f;
  57. public virtual void ResetBall()
  58. {
  59. UpdateOnPaddle();
  60. velocity = Vector2D.Zero;
  61. }
  62. public class RunBall : UpdateBehavior
  63. {
  64. public override void Update(IEnumerable<Entity> entities)
  65. {
  66. foreach (var entity in entities)
  67. {
  68. var ball = (Ball)entity;
  69. if (ball.isOnPaddle)
  70. ball.UpdateOnPaddle();
  71. else
  72. ball.UpdateInFlight(Time.Delta);
  73. const float Aspect = 1;
  74. ball.DrawArea = Rectangle.FromCenter(ball.Position, new Size(Height / Aspect, Height));
  75. }
  76. }
  77. }
  78. public Vector2D Position { get; protected set; }
  79. public static readonly Size BallSize = new Size(Height);
  80. private const float Height = Radius * 2.0f;
  81. internal const float Radius = 0.02f;
  82. protected virtual void UpdateInFlight(float timeDelta)
  83. {
  84. Position += velocity * timeDelta;
  85. HandleBorderCollisions();
  86. HandlePaddleCollision();
  87. }
  88. private void HandleBorderCollisions()
  89. {
  90. if (Position.X < Radius)
  91. HandleBorderCollision(Direction.Left);
  92. else if (Position.X > 1.0f - Radius)
  93. HandleBorderCollision(Direction.Right);
  94. if (Position.Y < Radius)
  95. HandleBorderCollision(Direction.Top);
  96. else if (Position.Y > 1.0f - Radius)
  97. HandleBorderCollision(Direction.Bottom);
  98. }
  99. protected enum Direction
  100. {
  101. Left,
  102. Top,
  103. Right,
  104. Bottom,
  105. }
  106. protected void ReflectVelocity(Direction collisionSide)
  107. {
  108. switch (collisionSide)
  109. {
  110. case Direction.Left:
  111. velocity.X = Math.Abs(velocity.X);
  112. break;
  113. case Direction.Top:
  114. velocity.Y = Math.Abs(velocity.Y);
  115. break;
  116. case Direction.Right:
  117. velocity.X = -Math.Abs(velocity.X);
  118. break;
  119. case Direction.Bottom:
  120. velocity.Y = -Math.Abs(velocity.Y);
  121. break;
  122. }
  123. }
  124. private void HandleBorderCollision(Direction collisionAtBorder)
  125. {
  126. ReflectVelocity(collisionAtBorder);
  127. if (collisionAtBorder == Direction.Bottom)
  128. ResetBall();
  129. else
  130. collisionSound.Play();
  131. }
  132. private void HandlePaddleCollision()
  133. {
  134. if (IsInAreaOfPaddle())
  135. SetNewVelocityAfterPaddleCollision();
  136. }
  137. private bool IsInAreaOfPaddle()
  138. {
  139. if (Position.Y + Radius > paddle.Position.Y && velocity.Y > 0)
  140. return Position.X + Radius > paddle.Position.X - Paddle.HalfWidth &&
  141. Position.X - Radius < paddle.Position.X + Paddle.HalfWidth;
  142. return false;
  143. }
  144. private void SetNewVelocityAfterPaddleCollision()
  145. {
  146. velocity.X += (Position.X - paddle.Position.X) * SpeedXIncrease;
  147. velocity.Y = -Math.Abs(velocity.Y) * SpeedYIncrease;
  148. float speed = velocity.Length;
  149. if (speed > MaximumScalarSpeed)
  150. velocity *= MaximumScalarSpeed / speed; //ncrunch: no coverage
  151. collisionSound.Play();
  152. }
  153. private const float SpeedYIncrease = 1.015f;
  154. private const float SpeedXIncrease = 2.5f;
  155. private const float MaximumScalarSpeed = 1.2f;
  156. public override void Dispose()
  157. {
  158. paddle.Dispose();
  159. base.Dispose();
  160. }
  161. }
  162. }