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