AnimatedGameComponent.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. //-----------------------------------------------------------------------------
  2. // AnimatedGameComponent.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 System.Text;
  10. using Microsoft.Xna.Framework;
  11. using Microsoft.Xna.Framework.Graphics;
  12. using CardsFramework;
  13. namespace CardsFramework
  14. {
  15. /// <summary>
  16. /// A game component.
  17. /// Enable variable display while managing and displaying a set of
  18. /// <see cref="AnimatedGameComponentAnimation">Animations</see>
  19. /// </summary>
  20. public class AnimatedGameComponent : DrawableGameComponent
  21. {
  22. public Texture2D CurrentFrame { get; set; }
  23. public Rectangle? CurrentSegment { get; set; }
  24. public string Text { get; set; }
  25. public Color TextColor { get; set; }
  26. public Color Color { get; set; } = Color.White; // Tint color for the sprite
  27. public bool IsFaceDown = true;
  28. public Vector2 CurrentPosition { get; set; }
  29. public Rectangle? CurrentDestination { get; set; }
  30. public float CurrentRotation { get; set; } = 0f;
  31. List<AnimatedGameComponentAnimation> runningAnimations =
  32. new List<AnimatedGameComponentAnimation>();
  33. /// <summary>
  34. /// Whether or not an animation belonging to the component is running.
  35. /// </summary>
  36. public virtual bool IsAnimating { get { return runningAnimations.Count > 0; } }
  37. public CardsGame CardGame { get; private set; }
  38. private SpriteBatch spriteBatch;
  39. private Matrix globalTransformation;
  40. /// <summary>
  41. /// Initializes a new instance of the class, using black text color.
  42. /// </summary>
  43. /// <param name="cardGame">The associated card game.</param>
  44. /// <param name="currentFrame">The texture serving as the current frame
  45. /// to display as the component.</param>
  46. public AnimatedGameComponent(CardsGame cardGame, Texture2D currentFrame, SpriteBatch sharedSpriteBatch, Matrix? globalTransformation = null)
  47. : base(cardGame.Game)
  48. {
  49. if (sharedSpriteBatch == null)
  50. throw new ArgumentNullException(nameof(sharedSpriteBatch), "AnimatedGameComponent requires a valid SpriteBatch.");
  51. CardGame = cardGame;
  52. CurrentFrame = currentFrame;
  53. TextColor = Color.Black;
  54. this.spriteBatch = sharedSpriteBatch;
  55. this.globalTransformation = globalTransformation ?? Matrix.Identity;
  56. }
  57. /// <summary>
  58. /// Keeps track of the component's animations.
  59. /// </summary>
  60. /// <param name="gameTime">The time which as elapsed since the last call
  61. /// to this method.</param>
  62. public override void Update(GameTime gameTime)
  63. {
  64. base.Update(gameTime);
  65. // Iterate backwards to safely remove completed animations
  66. for (int animationIndex = runningAnimations.Count - 1; animationIndex >= 0; animationIndex--)
  67. {
  68. runningAnimations[animationIndex].AccumulateElapsedTime(gameTime.ElapsedGameTime);
  69. runningAnimations[animationIndex].Run(gameTime);
  70. if (runningAnimations[animationIndex].IsDone())
  71. {
  72. runningAnimations.RemoveAt(animationIndex);
  73. }
  74. }
  75. }
  76. /// <summary>
  77. /// Draws the animated component and its associated text, if it exists, at
  78. /// the object's set destination. If a destination is not set, its initial
  79. /// position is used.
  80. /// </summary>
  81. /// <param name="gameTime">The time which as elapsed since the last call
  82. /// to this method.</param>
  83. public override void Draw(GameTime gameTime)
  84. {
  85. spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, globalTransformation);
  86. if (CurrentFrame != null)
  87. {
  88. // Calculate origin point (center of texture for rotation)
  89. Vector2 origin = new Vector2(CurrentFrame.Width / 2f, CurrentFrame.Height / 2f);
  90. // Draw at the destination if one is set
  91. if (CurrentDestination.HasValue)
  92. {
  93. // When using destination rectangle with rotation, we need center position
  94. Vector2 centerPosition = new Vector2(
  95. CurrentDestination.Value.X + CurrentDestination.Value.Width / 2f,
  96. CurrentDestination.Value.Y + CurrentDestination.Value.Height / 2f);
  97. // Calculate scale to match destination size
  98. Vector2 scale = new Vector2(
  99. CurrentDestination.Value.Width / (float)CurrentFrame.Width,
  100. CurrentDestination.Value.Height / (float)CurrentFrame.Height);
  101. spriteBatch.Draw(CurrentFrame, centerPosition, CurrentSegment, Color,
  102. CurrentRotation, origin, scale, SpriteEffects.None, 0f);
  103. if (Text != null)
  104. {
  105. Vector2 size = CardGame.Font.MeasureString(Text);
  106. Vector2 textPosition = new Vector2(centerPosition.X - size.X / 2,
  107. centerPosition.Y - size.Y / 2);
  108. spriteBatch.DrawString(CardGame.Font, Text, textPosition, TextColor);
  109. }
  110. }
  111. // Draw at the component's position if there is no destination
  112. else
  113. {
  114. // Position + origin to center the rotation point
  115. Vector2 centerPosition = CurrentPosition + origin;
  116. spriteBatch.Draw(CurrentFrame, centerPosition, CurrentSegment, Color,
  117. CurrentRotation, origin, 1f, SpriteEffects.None, 0f);
  118. if (Text != null)
  119. {
  120. Vector2 size = CardGame.Font.MeasureString(Text);
  121. Vector2 textPosition = new Vector2(centerPosition.X - size.X / 2,
  122. centerPosition.Y - size.Y / 2);
  123. spriteBatch.DrawString(CardGame.Font, Text, textPosition, TextColor);
  124. }
  125. }
  126. }
  127. spriteBatch.End();
  128. base.Draw(gameTime);
  129. }
  130. /// <summary>
  131. /// Adds an animation to the animated component.
  132. /// </summary>
  133. /// <param name="animation">The animation to add.</param>
  134. public void AddAnimation(AnimatedGameComponentAnimation animation)
  135. {
  136. animation.Component = this;
  137. runningAnimations.Add(animation);
  138. }
  139. /// <summary>
  140. /// Calculate the estimated time at which the longest lasting animation currently managed
  141. /// will complete.
  142. /// </summary>
  143. /// <returns>The estimated time for animation complete </returns>
  144. public virtual TimeSpan EstimatedTimeForAnimationsCompletion()
  145. {
  146. TimeSpan result = TimeSpan.Zero;
  147. if (IsAnimating)
  148. {
  149. for (int animationIndex = 0; animationIndex < runningAnimations.Count; animationIndex++)
  150. {
  151. if (runningAnimations[animationIndex].EstimatedTimeForAnimationCompletion > result)
  152. {
  153. result = runningAnimations[animationIndex].EstimatedTimeForAnimationCompletion;
  154. }
  155. }
  156. }
  157. return result;
  158. }
  159. }
  160. }