PageRenderTime 103ms CodeModel.GetById 60ms app.highlight 11ms RepoModel.GetById 29ms app.codeStats 0ms

/Samples/Breakout/Ball.cs

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