AnimationTests.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // Copyright (c) Craftwork Games. All rights reserved.
  2. // Licensed under the MIT license.
  3. // See LICENSE file in the project root for full license information.
  4. using System;
  5. using Microsoft.Xna.Framework;
  6. using Xunit;
  7. using MonoGame.Extended.Animations;
  8. namespace MonoGame.Extended.Tests.Animations;
  9. public class AnimationTests
  10. {
  11. private class TestAnimationFrame : IAnimationFrame
  12. {
  13. public int FrameIndex { get; set; }
  14. public TimeSpan Duration { get; set; }
  15. }
  16. private class TestAnimation : IAnimation
  17. {
  18. private readonly IAnimationFrame[] _frames;
  19. public string Name { get; set; }
  20. public ReadOnlySpan<IAnimationFrame> Frames => _frames;
  21. public int FrameCount { get; set; }
  22. public bool IsLooping { get; set; }
  23. public bool IsReversed { get; set; }
  24. public bool IsPingPong { get; set; }
  25. public TestAnimation(IAnimationFrame[] frames) => _frames = frames;
  26. }
  27. private readonly IAnimation _animation;
  28. private readonly IAnimationController _animationController;
  29. public AnimationTests()
  30. {
  31. var frames = new IAnimationFrame[]
  32. {
  33. new TestAnimationFrame { FrameIndex = 0, Duration = TimeSpan.FromSeconds(1) },
  34. new TestAnimationFrame { FrameIndex = 1, Duration = TimeSpan.FromSeconds(1) }
  35. };
  36. _animation = new TestAnimation(frames)
  37. {
  38. FrameCount = frames.Length,
  39. IsLooping = false,
  40. IsReversed = false,
  41. IsPingPong = false
  42. };
  43. _animationController = new AnimationController(_animation);
  44. }
  45. [Fact]
  46. public void Play_ShouldThrowException_ForInvalidFrame()
  47. {
  48. Assert.Throws<ArgumentOutOfRangeException>(() => _animationController.Play(-1));
  49. Assert.Throws<ArgumentOutOfRangeException>(() => _animationController.Play(10));
  50. }
  51. [Fact]
  52. public void Pause_ShouldPauseAnimation()
  53. {
  54. _animationController.Play();
  55. var result = _animationController.Pause();
  56. Assert.True(result);
  57. Assert.True(_animationController.IsPaused);
  58. }
  59. [Fact]
  60. public void Pause_ShouldResetFrameDuration_WhenSpecified()
  61. {
  62. _animationController.Play();
  63. _animationController.Update(new GameTime(TimeSpan.Zero, TimeSpan.FromSeconds(0.5)));
  64. var result = _animationController.Pause(true);
  65. Assert.True(result);
  66. Assert.Equal(_animation.Frames[0].Duration, _animationController.CurrentFrameTimeRemaining);
  67. }
  68. [Fact]
  69. public void UnPause_ShouldResumeAnimation()
  70. {
  71. _animationController.Play();
  72. _animationController.Pause();
  73. var result = _animationController.Unpause();
  74. Assert.True(result);
  75. Assert.False(_animationController.IsPaused);
  76. }
  77. [Fact]
  78. public void UnPause_ShouldAdvanceFrame_WhenSpecified()
  79. {
  80. _animationController.Play();
  81. _animationController.Pause();
  82. var result = _animationController.Unpause(true);
  83. Assert.True(result);
  84. Assert.Equal(1, _animationController.CurrentFrame);
  85. }
  86. [Fact]
  87. public void Stop_ShouldStopAnimation()
  88. {
  89. _animationController.Play();
  90. var result = _animationController.Stop();
  91. Assert.True(result);
  92. Assert.False(_animationController.IsAnimating);
  93. }
  94. [Fact]
  95. public void Update_ShouldAdvanceFrame()
  96. {
  97. _animationController.Play();
  98. _animationController.Update(new GameTime(TimeSpan.Zero, TimeSpan.FromSeconds(1.1)));
  99. Assert.Equal(1, _animationController.CurrentFrame);
  100. }
  101. [Fact]
  102. public void Update_ShouldTriggerAnimationEvents()
  103. {
  104. bool frameBeginTriggered = false;
  105. bool frameEndTriggered = false;
  106. bool animationLoopTriggered = false;
  107. bool animationCompletedTriggered = false;
  108. _animationController.OnAnimationEvent += (anim, trigger) =>
  109. {
  110. switch (trigger)
  111. {
  112. case AnimationEventTrigger.FrameBegin:
  113. frameBeginTriggered = true;
  114. break;
  115. case AnimationEventTrigger.FrameEnd:
  116. frameEndTriggered = true;
  117. break;
  118. case AnimationEventTrigger.AnimationLoop:
  119. animationLoopTriggered = true;
  120. break;
  121. case AnimationEventTrigger.AnimationCompleted:
  122. animationCompletedTriggered = true;
  123. break;
  124. }
  125. };
  126. _animationController.Play();
  127. _animationController.Update(new GameTime(TimeSpan.Zero, TimeSpan.FromSeconds(1.1)));
  128. Assert.True(frameBeginTriggered);
  129. Assert.True(frameEndTriggered);
  130. _animationController.IsLooping = true;
  131. _animationController.Update(new GameTime(TimeSpan.Zero, TimeSpan.FromSeconds(1.1)));
  132. Assert.True(animationLoopTriggered);
  133. _animationController.IsLooping = false;
  134. _animationController.Update(new GameTime(TimeSpan.Zero, TimeSpan.FromSeconds(2)));
  135. Assert.True(animationCompletedTriggered);
  136. }
  137. [Fact]
  138. public void Update_ShouldLoopAnimation()
  139. {
  140. _animationController.IsLooping = true;
  141. _animationController.Play();
  142. _animationController.Update(new GameTime(TimeSpan.Zero, TimeSpan.FromSeconds(2.1)));
  143. Assert.Equal(0, _animationController.CurrentFrame);
  144. }
  145. [Fact]
  146. public void Reset_ShouldResetAnimation()
  147. {
  148. _animationController.Play();
  149. _animationController.Reset();
  150. Assert.False(_animationController.IsAnimating);
  151. Assert.True(_animationController.IsPaused);
  152. Assert.Equal(0, _animationController.CurrentFrame);
  153. }
  154. [Fact]
  155. public void SetFrame_ShouldChangeCurrentFrame()
  156. {
  157. _animationController.SetFrame(1);
  158. Assert.Equal(1, _animationController.CurrentFrame);
  159. Assert.Equal(_animation.Frames[1].Duration, _animationController.CurrentFrameTimeRemaining);
  160. }
  161. [Fact]
  162. public void SetFrame_ShouldThrowException_ForInvalidFrame()
  163. {
  164. Assert.Throws<ArgumentOutOfRangeException>(() => _animationController.SetFrame(-1));
  165. Assert.Throws<ArgumentOutOfRangeException>(() => _animationController.SetFrame(10));
  166. }
  167. [Fact]
  168. public void Dispose_ShouldDisposeAnimation()
  169. {
  170. _animationController.Dispose();
  171. Assert.True(_animationController.IsDisposed);
  172. }
  173. [Fact]
  174. public void Update_WithTimeSpan_ShouldAdvanceFrame()
  175. {
  176. _animationController.Play();
  177. _animationController.Update(TimeSpan.FromSeconds(1.1));
  178. Assert.Equal(1, _animationController.CurrentFrame);
  179. }
  180. [Fact]
  181. public void Update_WithGameTime_ShouldProduceSameResultAsTimeSpan()
  182. {
  183. var frames = new IAnimationFrame[]
  184. {
  185. new TestAnimationFrame { FrameIndex = 0, Duration = TimeSpan.FromSeconds(1) },
  186. new TestAnimationFrame { FrameIndex = 1, Duration = TimeSpan.FromSeconds(1) }
  187. };
  188. var animation = new TestAnimation(frames)
  189. {
  190. FrameCount = frames.Length,
  191. IsLooping = false,
  192. IsReversed = false,
  193. IsPingPong = false
  194. };
  195. var controller1 = new AnimationController(animation);
  196. var controller2 = new AnimationController(animation);
  197. controller1.Play();
  198. controller2.Play();
  199. var elapsed = TimeSpan.FromSeconds(0.5);
  200. var gameTime = new GameTime(TimeSpan.Zero, elapsed);
  201. controller1.Update(gameTime);
  202. controller2.Update(elapsed);
  203. Assert.Equal(controller1.CurrentFrame, controller2.CurrentFrame);
  204. Assert.Equal(controller1.CurrentFrameTimeRemaining, controller2.CurrentFrameTimeRemaining);
  205. }
  206. }