/spacey

To get this branch, use:
bzr branch http://9ix.org/bzr/spacey

« back to all changes in this revision

Viewing changes to zoetrope/sprites/animation.lua

  • Committer: Josh C
  • Date: 2013-05-04 20:45:17 UTC
  • Revision ID: josh@9ix.org-20130504204517-1rfp92svud12kg42
zoetrope 1.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
-- Class: Animation
 
2
-- An animation displays a sequence of frames. If you do not specify
 
3
-- a width and height for the sprite, it will size itself so that
 
4
-- it is a square, where each side is as tall as the source image's height.
 
5
--
 
6
--
 
7
-- Event: onEndSequence
 
8
-- Called whenever an animation sequence ends. It is passed the name
 
9
-- of the sequence that just ended.
 
10
-- 
 
11
-- Extends:
 
12
--              <Sprite>
 
13
 
 
14
Animation = Sprite:extend{
 
15
        -- Property: paused
 
16
        -- Set this to true to freeze the animation on the current frame.
 
17
        paused = false,
 
18
 
 
19
        -- Property: sequences
 
20
        -- A lookup table of sequences. Each one is stored by name and has
 
21
        -- the following properties:
 
22
        -- * name - string name for the sequence.
 
23
        -- * frames - table of frames to display. The first frame in the sheet is at index 1.
 
24
        -- * fps - frames per second.
 
25
        -- * loops - does the animation loop? defaults to true
 
26
        sequences = {},
 
27
 
 
28
        -- Property: image
 
29
        -- A string filename to the image to use as a sprite strip. A sprite
 
30
        -- strip can have multiple rows of frames.
 
31
 
 
32
        -- Property: currentSequence
 
33
        -- A reference to the current animation sequence table.
 
34
 
 
35
        -- Property: currentName
 
36
        -- The name of the current animation sequence.
 
37
 
 
38
        -- Property: currentFrame
 
39
        -- The current frame being displayed; starts at 1.
 
40
 
 
41
        -- Property: frameIndex
 
42
        -- Numeric index of the current frame in the current sequence; starts at 1.
 
43
 
 
44
        -- Property: frameTimer
 
45
        -- Time left before the animation changes to the next frame in seconds.
 
46
        -- Normally you shouldn't need to change this directly.
 
47
 
 
48
        -- private property: used to check whether the source image
 
49
        -- for our quad is up-to-date
 
50
        _set = {},
 
51
 
 
52
        -- private property imageObj: actual Image instance used to draw
 
53
        -- this is normally set via the image property, but you may set it directly
 
54
        -- so long as you never change that image property afterwards.
 
55
 
 
56
        new = function (self, obj)
 
57
                obj = obj or {}
 
58
                self:extend(obj)
 
59
                obj:updateQuad()
 
60
 
 
61
                if obj.onNew then obj:onNew() end
 
62
                return obj
 
63
        end,
 
64
 
 
65
        -- Method: play 
 
66
        -- Begins playing an animation in the sprite's library.
 
67
        -- If the animation is already playing, this has no effect.
 
68
        --
 
69
        -- Arguments:
 
70
        --              name - name of the animation
 
71
        --
 
72
        -- Returns:
 
73
        --              nothing
 
74
 
 
75
        play = function (self, name)
 
76
                if self.currentName == name and not self.paused then
 
77
                        return
 
78
                end
 
79
                
 
80
                assert(self.sequences[name], 'no animation sequence named "' .. name .. '"')
 
81
                
 
82
                self.currentName = name
 
83
                self.currentSequence = self.sequences[name]
 
84
                self.frameIndex = 0
 
85
                self.frameTimer = 0
 
86
                self.paused = false
 
87
        end,
 
88
 
 
89
        -- Method: freeze
 
90
        -- Freezes the animation on the specified frame.
 
91
        --
 
92
        -- Arguments:
 
93
        --              * index - integer frame index relative to the entire sprite sheet,
 
94
        --                                starts at 1. If omitted, this freezes the current frame.
 
95
        --                                If there is no current frame, this freezes on the first frame.
 
96
        --
 
97
        -- Returns:
 
98
        --              nothing
 
99
 
 
100
        freeze = function (self, index)
 
101
                if self.currentSequence then
 
102
                        index = index or self.currentSequence[self.frameIndex]
 
103
                end
 
104
                
 
105
                index = index or self.currentFrame or 1
 
106
 
 
107
                if self._set.image ~= self.image then
 
108
                        self:updateQuad()
 
109
                end
 
110
 
 
111
                self.currentFrame = index
 
112
                self:updateFrame(index)
 
113
                self.paused = true
 
114
        end,
 
115
 
 
116
        -- private method: updateQuad
 
117
        -- sets up the sprite's quad property based on the image;
 
118
        -- needs to be called whenever the sprite's image property changes.
 
119
        --
 
120
        -- Arguments:
 
121
        --              none
 
122
        --
 
123
        -- Returns:
 
124
        --              nothing
 
125
 
 
126
        updateQuad = function (self)
 
127
                if self.image then 
 
128
                        self._imageObj = Cached:image(self.image)
 
129
                        if not self.width then self.width = self._imageObj:getHeight() end
 
130
                        if not self.height then self.height = self.width end
 
131
 
 
132
                        self._quad = love.graphics.newQuad(0, 0, self.width, self.height,
 
133
                                                                                          self._imageObj:getWidth(), self._imageObj:getHeight())
 
134
                        self._imageWidth = self._imageObj:getWidth()
 
135
                        self._set.image = self.image
 
136
                end
 
137
        end,
 
138
 
 
139
        -- private method: updateFrame
 
140
        -- changes the sprite's quad property based on the current frame;
 
141
        -- needs to be called whenever the sprite's currentFrame property changes.
 
142
        --
 
143
        -- Arguments:
 
144
        --              none
 
145
        --
 
146
        -- Returns:
 
147
        --              nothing
 
148
 
 
149
        updateFrame = function (self)
 
150
                assert(type(self.currentFrame) == 'number', "current frame is not a number")
 
151
                assert(self.image, "asked to set the frame of a nil image")
 
152
 
 
153
                if self._set.image ~= self.image then
 
154
                        self:updateQuad()
 
155
                end
 
156
 
 
157
                local frameX = (self.currentFrame - 1) * self.width
 
158
                local viewportX = frameX % self._imageWidth
 
159
                local viewportY = self.height * math.floor(frameX / self._imageWidth)
 
160
                self._quad:setViewport(viewportX, viewportY, self.width, self.height)
 
161
        end,
 
162
 
 
163
        update = function (self, elapsed)
 
164
                -- move the animation frame forward
 
165
 
 
166
                if self.currentSequence and not self.paused then
 
167
                        self.frameTimer = self.frameTimer - elapsed
 
168
                        
 
169
                        if self.frameTimer <= 0 then
 
170
                                self.frameIndex = self.frameIndex + 1
 
171
 
 
172
                                if self.frameIndex > #self.currentSequence.frames then
 
173
                                        if self.onEndSequence then self:onEndSequence(self.currentName) end
 
174
 
 
175
                                        if self.currentSequence.loops ~= false then
 
176
                                                self.frameIndex = 1
 
177
                                        else
 
178
                                                self.frameIndex = self.frameIndex - 1
 
179
                                                self.paused = true
 
180
                                        end
 
181
                                end
 
182
 
 
183
                                self.currentFrame = self.currentSequence.frames[self.frameIndex]
 
184
                                self:updateFrame()
 
185
                                self.frameTimer = 1 / self.currentSequence.fps
 
186
                        end
 
187
                end
 
188
 
 
189
                Sprite.update(self, elapsed)
 
190
        end,
 
191
 
 
192
        draw = function (self, x, y)
 
193
                x = math.floor(x or self.x)
 
194
                y = math.floor(y or self.y)
 
195
 
 
196
                if STRICT then
 
197
                        assert(type(x) == 'number', 'visible animation does not have a numeric x property')
 
198
                        assert(type(y) == 'number', 'visible animation does not have a numeric y property')
 
199
                        assert(type(self.width) == 'number', 'visible animation does not have a numeric width property')
 
200
                        assert(type(self.height) == 'number', 'visible animation does not have a numeric height property')
 
201
                end
 
202
 
 
203
                if not self.visible or not self.image or self.alpha <= 0 then return end
 
204
                
 
205
                -- if our image changed, update the quad
 
206
                
 
207
                if self._set.image ~= self.image then
 
208
                        self:updateQuad()
 
209
                end
 
210
                
 
211
                -- set color if needed
 
212
 
 
213
                local colored = self.alpha ~= 1 or self.tint[1] ~= 1 or self.tint[2] ~= 1 or self.tint[3] ~= 1
 
214
 
 
215
                if colored then
 
216
                        love.graphics.setColor(self.tint[1] * 255, self.tint[2] * 255, self.tint[3] * 255, self.alpha * 255)
 
217
                end
 
218
 
 
219
                -- draw the quad
 
220
 
 
221
                local scaleX = self.scale * self.distort.x
 
222
                local scaleY = self.scale * self.distort.y
 
223
 
 
224
                if self.flipX then scaleX = scaleX * -1 end
 
225
                if self.flipY then scaleY = scaleY * -1 end
 
226
                        
 
227
                love.graphics.drawq(self._imageObj, self._quad, x + self.width / 2, y + self.height / 2, self.rotation,
 
228
                                                        scaleX, scaleY, self.width / 2, self.height / 2)
 
229
                
 
230
                -- reset color
 
231
                
 
232
                if colored then
 
233
                        love.graphics.setColor(255, 255, 255, 255)
 
234
                end
 
235
        end,
 
236
 
 
237
        __tostring = function (self)
 
238
                local result = 'Animation (x: ' .. self.x .. ', y: ' .. self.y ..
 
239
                                           ', w: ' .. self.width .. ', h: ' .. self.height .. ', '
 
240
 
 
241
                if self.currentName then
 
242
                        result = result .. 'playing ' .. self.currentName .. ', '
 
243
                end
 
244
 
 
245
                result = result .. ' frame ' .. self.currentFrame .. ', '
 
246
 
 
247
                if self.active then
 
248
                        result = result .. 'active, '
 
249
                else
 
250
                        result = result .. 'inactive, '
 
251
                end
 
252
 
 
253
                if self.visible then
 
254
                        result = result .. 'visible, '
 
255
                else
 
256
                        result = result .. 'invisible, '
 
257
                end
 
258
 
 
259
                if self.solid then
 
260
                        result = result .. 'solid'
 
261
                else
 
262
                        result = result .. 'not solid'
 
263
                end
 
264
 
 
265
                return result .. ')'
 
266
        end
 
267
}