1 module prova.graphics.sprites.animatedsprite;
2 
3 import derelict.sdl2.sdl,
4        prova.graphics,
5        prova.math,
6        std.math;
7 
8 ///
9 class AnimatedSprite : Sprite
10 {
11   private SpriteAnimation[string] animations;
12   private SpriteAnimation currentAnimation;
13   private SpriteFrame currentFrame;
14   private uint startTime;
15   private float frameEndTime;
16   private int currentFrameIndex;
17   private bool looping;
18 
19   ///
20   this(SpriteSheet sheet)
21   {
22     animations = sheet.animations;
23     texture = sheet.texture;
24   }
25 
26   ///
27   void playAnimation(string name, bool loop = false)
28   { 
29     if(!(name in animations))
30       throw new Exception("Animation " ~ name ~ " does not exist");
31 
32     currentAnimation = animations[name];
33     looping = loop;
34     reset();
35 
36     update();
37   }
38 
39   ///
40   bool isAnimationFinished()
41   {
42     if(!currentAnimation)
43       return true;
44 
45     return getCurrentTime() == currentAnimation.getDuration();
46   }
47 
48   ///
49   bool isLooping()
50   {
51     return looping;
52   }
53 
54   ///
55   float getCurrentTime()
56   {
57     float currentTime = SDL_GetTicks() - startTime;
58     currentTime /= 1000.0f;
59 
60     float animationDuration = currentAnimation.getDuration();
61 
62     if(looping)
63       currentTime = fmod(currentTime, animationDuration);
64     else if(currentTime > animationDuration)
65       currentTime = animationDuration;
66 
67     return currentTime;
68   }
69 
70   /// Returns the index of the current frame within the current animation
71   int getCurrentFrame()
72   {
73     if(!currentAnimation)
74       return 0;
75 
76     return currentFrameIndex;
77   }
78 
79   /// Returns the name of the current animation
80   string getCurrentAnimation()
81   {
82     if(!currentAnimation)
83       return null;
84 
85     return currentAnimation.name;
86   }
87 
88   /// Usually unnecessary to call directly
89   void update()
90   {
91     if(!currentAnimation)
92       return;
93 
94     updateCurrentFrame();
95 
96     clip = currentFrame.clip;
97   }
98 
99   private void updateCurrentFrame()
100   {
101     float currentTime = SDL_GetTicks() - startTime;
102     currentTime /= 1000.0f;
103 
104     while(currentTime > frameEndTime) {
105       if(++currentFrameIndex >= currentAnimation.frames.length) {
106         if(looping)
107           reset();
108         else
109           currentFrameIndex -= 1;
110 
111         break;
112       }
113 
114       currentFrame = currentAnimation.frames[currentFrameIndex];
115       frameEndTime += currentFrame.duration;
116     }
117   }
118 
119   private void reset()
120   {
121     currentFrameIndex = 0;
122     currentFrame = currentAnimation.frames[0];
123     frameEndTime = currentFrame.duration;
124     startTime = SDL_GetTicks();
125   }
126 }