MessageDisplayComponent.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // MessageDisplayComponent.cs
  4. //
  5. // Microsoft XNA Community Game Platform
  6. // Copyright (C) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9. #region Using Statements
  10. using System;
  11. using System.Collections.Generic;
  12. using Microsoft.Xna.Framework;
  13. using Microsoft.Xna.Framework.Graphics;
  14. #endregion
  15. namespace NetworkStateManagement
  16. {
  17. /// <summary>
  18. /// Component implements the IMessageDisplay interface. This is used to show
  19. /// notification messages when interesting events occur, for instance when
  20. /// gamers join or leave the network session
  21. /// </summary>
  22. class MessageDisplayComponent : DrawableGameComponent, IMessageDisplay
  23. {
  24. #region Fields
  25. SpriteBatch spriteBatch;
  26. SpriteFont font;
  27. // List of the currently visible notification messages.
  28. List<NotificationMessage> messages = new List<NotificationMessage>();
  29. // Coordinates threadsafe access to the message list.
  30. object syncObject = new object();
  31. // Tweakable settings control how long each message is visible.
  32. static readonly TimeSpan fadeInTime = TimeSpan.FromSeconds(0.25);
  33. static readonly TimeSpan showTime = TimeSpan.FromSeconds(5);
  34. static readonly TimeSpan fadeOutTime = TimeSpan.FromSeconds(0.5);
  35. #endregion
  36. #region Initialization
  37. /// <summary>
  38. /// Constructs a new message display component.
  39. /// </summary>
  40. public MessageDisplayComponent(Game game)
  41. : base(game)
  42. {
  43. // Register ourselves to implement the IMessageDisplay service.
  44. game.Services.AddService(typeof(IMessageDisplay), this);
  45. }
  46. /// <summary>
  47. /// Load graphics content for the message display.
  48. /// </summary>
  49. protected override void LoadContent()
  50. {
  51. spriteBatch = new SpriteBatch(GraphicsDevice);
  52. font = Game.Content.Load<SpriteFont>("menufont");
  53. }
  54. #endregion
  55. #region Update and Draw
  56. /// <summary>
  57. /// Updates the message display component.
  58. /// </summary>
  59. public override void Update(GameTime gameTime)
  60. {
  61. lock (syncObject)
  62. {
  63. int index = 0;
  64. float targetPosition = 0;
  65. // Update each message in turn.
  66. while (index < messages.Count)
  67. {
  68. NotificationMessage message = messages[index];
  69. // Gradually slide the message toward its desired position.
  70. float positionDelta = targetPosition - message.Position;
  71. float velocity = (float)gameTime.ElapsedGameTime.TotalSeconds * 2;
  72. message.Position += positionDelta * Math.Min(velocity, 1);
  73. // Update the age of the message.
  74. message.Age += gameTime.ElapsedGameTime;
  75. if (message.Age < showTime + fadeOutTime)
  76. {
  77. // This message is still alive.
  78. index++;
  79. // Any subsequent messages should be positioned below
  80. // this one, unless it has started to fade out.
  81. if (message.Age < showTime)
  82. targetPosition++;
  83. }
  84. else
  85. {
  86. // This message is old, and should be removed.
  87. messages.RemoveAt(index);
  88. }
  89. }
  90. }
  91. }
  92. /// <summary>
  93. /// Draws the message display component.
  94. /// </summary>
  95. public override void Draw(GameTime gameTime)
  96. {
  97. lock (syncObject)
  98. {
  99. // Early out if there are no messages to display.
  100. if (messages.Count == 0)
  101. return;
  102. Vector2 position = new Vector2(GraphicsDevice.Viewport.Width - 100, 0);
  103. spriteBatch.Begin();
  104. // Draw each message in turn.
  105. foreach (NotificationMessage message in messages)
  106. {
  107. const float scale = 0.75f;
  108. // Compute the alpha of this message.
  109. float alpha = 1;
  110. if (message.Age < fadeInTime)
  111. {
  112. // Fading in.
  113. alpha = (float)(message.Age.TotalSeconds /
  114. fadeInTime.TotalSeconds);
  115. }
  116. else if (message.Age > showTime)
  117. {
  118. // Fading out.
  119. TimeSpan fadeOut = showTime + fadeOutTime - message.Age;
  120. alpha = (float)(fadeOut.TotalSeconds /
  121. fadeOutTime.TotalSeconds);
  122. }
  123. // Compute the message position.
  124. position.Y = 80 + message.Position * font.LineSpacing * scale;
  125. // Compute an origin value to right align each message.
  126. Vector2 origin = font.MeasureString(message.Text);
  127. origin.Y = 0;
  128. // Draw the message text, with a drop shadow.
  129. spriteBatch.DrawString(font, message.Text, position + Vector2.One,
  130. Color.Black * alpha, 0,
  131. origin, scale, SpriteEffects.None, 0);
  132. spriteBatch.DrawString(font, message.Text, position,
  133. Color.White * alpha, 0,
  134. origin, scale, SpriteEffects.None, 0);
  135. }
  136. spriteBatch.End();
  137. }
  138. }
  139. #endregion
  140. #region Implement IMessageDisplay
  141. /// <summary>
  142. /// Shows a new notification message.
  143. /// </summary>
  144. public void ShowMessage(string message, params object[] parameters)
  145. {
  146. string formattedMessage = string.Format(message, parameters);
  147. lock (syncObject)
  148. {
  149. float startPosition = messages.Count;
  150. messages.Add(new NotificationMessage(formattedMessage, startPosition));
  151. }
  152. }
  153. #endregion
  154. #region Nested Types
  155. /// <summary>
  156. /// Helper class stores the position and text of a single notification message.
  157. /// </summary>
  158. class NotificationMessage
  159. {
  160. public string Text;
  161. public float Position;
  162. public TimeSpan Age;
  163. public NotificationMessage(string text, float position)
  164. {
  165. Text = text;
  166. Position = position;
  167. Age = TimeSpan.Zero;
  168. }
  169. }
  170. #endregion
  171. }
  172. }