/ld27

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