MessageDisplayComponent.cs 6.7 KB

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