OverhandShuffleAnimation.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. //-----------------------------------------------------------------------------
  2. // OverhandShuffleAnimation.cs
  3. //
  4. // Implements an overhand shuffle animation where packets of cards are
  5. // repeatedly lifted from the back and dropped onto the front, creating
  6. // the most common casual shuffle pattern
  7. //-----------------------------------------------------------------------------
  8. using System;
  9. using System.Collections.Generic;
  10. using Microsoft.Xna.Framework;
  11. using Microsoft.Xna.Framework.Graphics;
  12. namespace CardsFramework
  13. {
  14. /// <summary>
  15. /// Overhand shuffle: repeatedly pull small packets from back and drop on front.
  16. /// Uses scaling to simulate depth (cards lifting toward camera appear larger).
  17. /// </summary>
  18. public class OverhandShuffleAnimation : ShuffleAnimation
  19. {
  20. // Animation timing ratios (must sum to 1.0)
  21. private const float LiftPhaseRatio = 0.3f;
  22. private const float TransferPhaseRatio = 0.4f;
  23. private const float DropPhaseRatio = 0.3f;
  24. // Card display settings
  25. private const int MaxVisibleCards = 15;
  26. private const int CardDisplayStep = 3; // Show every 3rd card
  27. private const float CardDepthSpacing = 0.5f;
  28. // Scale settings for depth illusion
  29. private const float TableScale = 1.0f; // Normal size on table
  30. private const float LiftedScale = 1.18f; // Larger when lifted (closer to camera)
  31. // Randomization ranges
  32. private const int FinalPositionRandomX = 5;
  33. private const int FinalPositionRandomY = 2;
  34. /// <summary>
  35. /// How high cards lift vertically (in pixels)
  36. /// </summary>
  37. public float LiftHeight { get; set; } = 70f;
  38. /// <summary>
  39. /// How far forward cards move during transfer (in pixels)
  40. /// </summary>
  41. public float ForwardDistance { get; set; } = 50f;
  42. /// <summary>
  43. /// Maximum rotation angle during lift (in radians)
  44. /// </summary>
  45. public float MaxRotation { get; set; } = 0.08f;
  46. /// <summary>
  47. /// Number of packets to shuffle (more packets = more realistic)
  48. /// </summary>
  49. public int PacketCount { get; set; } = 6;
  50. /// <summary>
  51. /// Creates a new overhand shuffle animation
  52. /// </summary>
  53. public OverhandShuffleAnimation(CardsGame cardGame, Vector2 position, TimeSpan duration, Vector2 cardSize)
  54. : base(cardGame, position, duration, cardSize)
  55. {
  56. }
  57. /// <summary>
  58. /// Creates the animated cards with overhand shuffle animations
  59. /// </summary>
  60. public override List<AnimatedCardsGameComponent> CreateAnimatedCards(
  61. List<TraditionalCard> deck,
  62. SpriteBatch spriteBatch,
  63. Matrix globalTransformation)
  64. {
  65. var animatedCards = new List<AnimatedCardsGameComponent>();
  66. // Only show a subset of cards for clear visual effect
  67. int cardsToShow = Math.Min(MaxVisibleCards, deck.Count / CardDisplayStep);
  68. int step = deck.Count / cardsToShow;
  69. // Calculate how many cards per packet
  70. int cardsPerPacket = Math.Max(1, cardsToShow / PacketCount);
  71. // Time calculations for animation phases
  72. TimeSpan packetInterval = TimeSpan.FromMilliseconds(Duration.TotalMilliseconds / PacketCount);
  73. TimeSpan liftDuration = TimeSpan.FromMilliseconds(packetInterval.TotalMilliseconds * LiftPhaseRatio);
  74. TimeSpan transferDuration = TimeSpan.FromMilliseconds(packetInterval.TotalMilliseconds * TransferPhaseRatio);
  75. TimeSpan dropDuration = TimeSpan.FromMilliseconds(packetInterval.TotalMilliseconds * DropPhaseRatio);
  76. for (int i = 0; i < cardsToShow; i++)
  77. {
  78. int deckIndex = i * step;
  79. if (deckIndex >= deck.Count) break;
  80. // Determine which packet this card belongs to
  81. int packetIndex = i / cardsPerPacket;
  82. if (packetIndex >= PacketCount) packetIndex = PacketCount - 1;
  83. // Create card component with slight vertical offset for depth
  84. float depthOffset = i * CardDepthSpacing;
  85. var cardComponent = CreateCardComponent(deck[deckIndex], spriteBatch, globalTransformation,
  86. Position + new Vector2(0, depthOffset), true);
  87. animatedCards.Add(cardComponent);
  88. // Calculate timing for this packet
  89. TimeSpan packetDelay = TimeSpan.FromMilliseconds(packetIndex * packetInterval.TotalMilliseconds);
  90. // Phase 1: Lift up (cards move toward camera, appear larger)
  91. Vector2 liftPosition = Position + new Vector2(0, -LiftHeight + depthOffset);
  92. AddTransition(
  93. cardComponent,
  94. liftPosition,
  95. packetDelay,
  96. liftDuration);
  97. // Scale up during lift (simulates moving toward camera)
  98. AddScale(
  99. cardComponent,
  100. TableScale,
  101. LiftedScale,
  102. packetDelay,
  103. liftDuration);
  104. // Slight tilt during lift for realism
  105. AddRotation(
  106. cardComponent,
  107. 0f,
  108. -MaxRotation,
  109. packetDelay,
  110. liftDuration);
  111. // Phase 2: Transfer forward over the pile
  112. Vector2 transferPosition = Position + new Vector2(ForwardDistance, -LiftHeight + depthOffset);
  113. AddTransition(
  114. cardComponent,
  115. transferPosition,
  116. packetDelay + liftDuration,
  117. transferDuration);
  118. // Stay scaled up during transfer (still elevated)
  119. AddScale(
  120. cardComponent,
  121. LiftedScale,
  122. LiftedScale,
  123. packetDelay + liftDuration,
  124. transferDuration);
  125. // Rotate back to flat
  126. AddRotation(
  127. cardComponent,
  128. -MaxRotation,
  129. 0f,
  130. packetDelay + liftDuration,
  131. transferDuration);
  132. // Phase 3: Drop onto pile (cards move away from camera, appear smaller)
  133. Vector2 finalPosition = Position + new Vector2(
  134. ForwardDistance + Random.Next(-FinalPositionRandomX, FinalPositionRandomX),
  135. depthOffset + Random.Next(-FinalPositionRandomY, FinalPositionRandomY));
  136. AddTransition(
  137. cardComponent,
  138. finalPosition,
  139. packetDelay + liftDuration + transferDuration,
  140. dropDuration);
  141. // Scale back down as card drops to table (moves away from camera)
  142. AddScale(
  143. cardComponent,
  144. LiftedScale,
  145. TableScale,
  146. packetDelay + liftDuration + transferDuration,
  147. dropDuration);
  148. }
  149. return animatedCards;
  150. }
  151. }
  152. }