MessageDisplayComponent.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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 CatapultGame
  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. font = Game.Content.Load<SpriteFont>("Fonts/MenuFont");
  47. }
  48. /// <summary>
  49. /// Updates the message display component.
  50. /// </summary>
  51. public override void Update(GameTime gameTime)
  52. {
  53. lock (syncObject)
  54. {
  55. int index = 0;
  56. float targetPosition = 0;
  57. // Update each message in turn.
  58. while (index < messages.Count)
  59. {
  60. NotificationMessage message = messages[index];
  61. // Gradually slide the message toward its desired position.
  62. float positionDelta = targetPosition - message.Position;
  63. float velocity = (float)gameTime.ElapsedGameTime.TotalSeconds * 2;
  64. message.Position += positionDelta * Math.Min(velocity, 1);
  65. // Update the age of the message.
  66. message.Age += gameTime.ElapsedGameTime;
  67. if (message.Age < showTime + fadeOutTime)
  68. {
  69. // This message is still alive.
  70. index++;
  71. // Any subsequent messages should be positioned below
  72. // this one, unless it has started to fade out.
  73. if (message.Age < showTime)
  74. targetPosition++;
  75. }
  76. else
  77. {
  78. // This message is old, and should be removed.
  79. messages.RemoveAt(index);
  80. }
  81. }
  82. }
  83. }
  84. /// <summary>
  85. /// Draws the message display component.
  86. /// </summary>
  87. public override void Draw(GameTime gameTime)
  88. {
  89. lock (syncObject)
  90. {
  91. // Early out if there are no messages to display.
  92. if (messages.Count == 0)
  93. return;
  94. Vector2 position = new Vector2(GraphicsDevice.Viewport.Width - 100, 0);
  95. spriteBatch.Begin();
  96. // Draw each message in turn.
  97. foreach (NotificationMessage message in messages)
  98. {
  99. const float scale = 0.75f;
  100. // Compute the alpha of this message.
  101. float alpha = 1;
  102. if (message.Age < fadeInTime)
  103. {
  104. // Fading in.
  105. alpha = (float)(message.Age.TotalSeconds /
  106. fadeInTime.TotalSeconds);
  107. }
  108. else if (message.Age > showTime)
  109. {
  110. // Fading out.
  111. TimeSpan fadeOut = showTime + fadeOutTime - message.Age;
  112. alpha = (float)(fadeOut.TotalSeconds /
  113. fadeOutTime.TotalSeconds);
  114. }
  115. // Compute the message position.
  116. position.Y = 80 + message.Position * font.LineSpacing * scale;
  117. // Compute an origin value to right align each message.
  118. Vector2 origin = font.MeasureString(message.Text);
  119. origin.Y = 0;
  120. // Draw the message text, with a drop shadow.
  121. spriteBatch.DrawString(font, message.Text, position + Vector2.One,
  122. Color.Black * alpha, 0,
  123. origin, scale, SpriteEffects.None, 0);
  124. spriteBatch.DrawString(font, message.Text, position,
  125. Color.White * alpha, 0,
  126. origin, scale, SpriteEffects.None, 0);
  127. }
  128. spriteBatch.End();
  129. }
  130. }
  131. /// <summary>
  132. /// Shows a new notification message.
  133. /// </summary>
  134. public void ShowMessage(string message, params object[] parameters)
  135. {
  136. string formattedMessage = string.Format(message, parameters);
  137. lock (syncObject)
  138. {
  139. float startPosition = messages.Count;
  140. messages.Add(new NotificationMessage(formattedMessage, startPosition));
  141. }
  142. }
  143. /// <summary>
  144. /// Helper class stores the position and text of a single notification message.
  145. /// </summary>
  146. class NotificationMessage
  147. {
  148. public string Text;
  149. public float Position;
  150. public TimeSpan Age;
  151. public NotificationMessage(string text, float position)
  152. {
  153. Text = text;
  154. Position = position;
  155. Age = TimeSpan.Zero;
  156. }
  157. }
  158. }
  159. }