ShuffleAnimationComponent.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. //-----------------------------------------------------------------------------
  2. // ShuffleAnimationComponent.cs
  3. //
  4. // Game component that manages a shuffle animation, creates and coordinates
  5. // all animated card components, and handles cleanup
  6. //-----------------------------------------------------------------------------
  7. using System;
  8. using System.Collections.Generic;
  9. using Microsoft.Xna.Framework;
  10. using Microsoft.Xna.Framework.Graphics;
  11. namespace CardsFramework
  12. {
  13. /// <summary>
  14. /// Component that orchestrates a shuffle animation by creating animated
  15. /// cards and managing their lifecycle
  16. /// </summary>
  17. public class ShuffleAnimationComponent : DrawableGameComponent
  18. {
  19. private readonly ShuffleAnimation shuffleAnimation;
  20. private readonly List<TraditionalCard> deck;
  21. private readonly SpriteBatch spriteBatch;
  22. private readonly Matrix globalTransformation;
  23. private List<AnimatedCardsGameComponent> animatedCards;
  24. private TimeSpan elapsedTime;
  25. private bool animationStarted = false;
  26. private bool animationCompleted = false;
  27. /// <summary>
  28. /// Gets whether the shuffle animation has completed
  29. /// </summary>
  30. public bool IsComplete => animationCompleted;
  31. /// <summary>
  32. /// Creates a new shuffle animation component
  33. /// </summary>
  34. /// <param name="game">The game instance</param>
  35. /// <param name="shuffleAnimation">The shuffle animation to perform</param>
  36. /// <param name="deck">The deck of cards to shuffle</param>
  37. /// <param name="spriteBatch">Shared sprite batch for rendering</param>
  38. /// <param name="globalTransformation">Transformation matrix for scaling</param>
  39. public ShuffleAnimationComponent(
  40. Game game,
  41. ShuffleAnimation shuffleAnimation,
  42. List<TraditionalCard> deck,
  43. SpriteBatch spriteBatch,
  44. Matrix globalTransformation)
  45. : base(game)
  46. {
  47. this.shuffleAnimation = shuffleAnimation;
  48. this.deck = deck;
  49. this.spriteBatch = spriteBatch;
  50. this.globalTransformation = globalTransformation;
  51. // Component should not be visible initially
  52. Visible = false;
  53. }
  54. /// <summary>
  55. /// Initialize and start the animation
  56. /// </summary>
  57. public override void Initialize()
  58. {
  59. base.Initialize();
  60. // Create all animated cards
  61. animatedCards = shuffleAnimation.CreateAnimatedCards(deck, spriteBatch, globalTransformation);
  62. // Initialize cards but don't add to Game.Components
  63. // (we'll update and draw them manually for better batching)
  64. foreach (var card in animatedCards)
  65. {
  66. card.Initialize();
  67. }
  68. // Make component visible and trigger start callback
  69. Visible = true;
  70. animationStarted = true;
  71. shuffleAnimation.OnAnimationStart?.Invoke();
  72. }
  73. /// <summary>
  74. /// Update animation progress and check for completion
  75. /// </summary>
  76. public override void Update(GameTime gameTime)
  77. {
  78. base.Update(gameTime);
  79. if (!animationStarted)
  80. return;
  81. elapsedTime += gameTime.ElapsedGameTime;
  82. // Update all animated cards
  83. if (animatedCards != null)
  84. {
  85. foreach (var card in animatedCards)
  86. {
  87. if (card.Enabled)
  88. card.Update(gameTime);
  89. }
  90. }
  91. // Check if animation duration has elapsed
  92. if (elapsedTime >= shuffleAnimation.Duration && !animationCompleted)
  93. {
  94. CompleteAnimation();
  95. }
  96. }
  97. /// <summary>
  98. /// Draw all cards in a single batched draw call
  99. /// </summary>
  100. public override void Draw(GameTime gameTime)
  101. {
  102. base.Draw(gameTime);
  103. if (!animationStarted || animatedCards == null)
  104. return;
  105. // Begin batch once for all cards
  106. spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, globalTransformation);
  107. // Draw all visible cards
  108. foreach (var card in animatedCards)
  109. {
  110. if (card.Visible)
  111. card.Draw(gameTime);
  112. }
  113. spriteBatch.End();
  114. }
  115. /// <summary>
  116. /// Called when animation finishes
  117. /// </summary>
  118. private void CompleteAnimation()
  119. {
  120. animationCompleted = true;
  121. // CRITICAL: Hide cards immediately before doing anything else
  122. // This prevents the "ghost deck" from appearing at shuffle position
  123. if (animatedCards != null)
  124. {
  125. foreach (var card in animatedCards)
  126. {
  127. card.Visible = false;
  128. }
  129. }
  130. // Invoke completion callback
  131. shuffleAnimation.OnAnimationComplete?.Invoke();
  132. // Clean up all card components
  133. CleanupCards();
  134. // Remove this component from the game
  135. Game.Components.Remove(this);
  136. }
  137. /// <summary>
  138. /// Removes all animated card components from the game
  139. /// </summary>
  140. private void CleanupCards()
  141. {
  142. if (animatedCards != null)
  143. {
  144. // Dispose all cards
  145. foreach (var card in animatedCards)
  146. {
  147. card.Visible = false;
  148. card.Dispose();
  149. }
  150. animatedCards.Clear();
  151. }
  152. }
  153. /// <summary>
  154. /// Dispose and cleanup
  155. /// </summary>
  156. protected override void Dispose(bool disposing)
  157. {
  158. if (disposing)
  159. {
  160. CleanupCards();
  161. }
  162. base.Dispose(disposing);
  163. }
  164. }
  165. }