-
Notifications
You must be signed in to change notification settings - Fork 7
/
base.gfx.sprite.frameanimation.bmx
343 lines (261 loc) · 8.86 KB
/
base.gfx.sprite.frameanimation.bmx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
SuperStrict
Import BRL.Map
Import BRL.Retro
Import "base.util.deltatimer.bmx"
Import "base.util.data.bmx"
Type TSpriteFrameAnimationCollection
Field animations:TMap = CreateMap()
Field currentAnimationName:string = ""
Method Copy:TSpriteFrameAnimationCollection()
local c:TSpriteFrameAnimationCollection = new TSpriteFrameAnimationCollection
c.animations = animations.Copy()
c.currentAnimationName = currentAnimationName
return c
End Method
Method InitFromData:TSpriteFrameAnimationCollection(data:TData)
For local animationData:TData = EachIn TData[](data.Get("animations"))
Set(new TSpriteFrameAnimation.InitFromData(animationData))
Next
local newCurrentAnimationName:string = data.GetString("currentAnimationName")
if newCurrentAnimationName then SetCurrent(newCurrentAnimationName)
return self
End Method
'insert a TSpriteFrameAnimation with a certain Name
Method Set(animation:TSpriteFrameAnimation, name:string="")
if name = "" then name = animation.name
animations.insert(lower(name), animation)
if not animations.contains("default") then setCurrent(name, 0)
End Method
'Set a new Animation
'If it is a different animation name, the Animation will get reset (start from begin)
Method SetCurrent(name:string, start:int = TRUE, reset:int = True)
name = lower(name)
'if reset is allowed, reset on a different name
if reset then reset = 1 - (currentAnimationName = name)
currentAnimationName = name
if reset then getCurrent().Reset()
if start then getCurrent().Playback()
End Method
Method GetCurrent:TSpriteFrameAnimation()
local obj:TSpriteFrameAnimation = TSpriteFrameAnimation(animations.ValueForKey(currentAnimationName))
'load default if nothing was found
if not obj then obj = TSpriteFrameAnimation(animations.ValueForKey("default"))
return obj
End Method
Method Get:TSpriteFrameAnimation(name:string="default")
local obj:TSpriteFrameAnimation = TSpriteFrameAnimation(animations.ValueForKey(name.toLower()))
if not obj then obj = TSpriteFrameAnimation(animations.ValueForKey("default"))
return obj
End Method
Method getCurrentAnimationName:string()
return currentAnimationName
End Method
Method Update:int(deltaTime:Float = -1.0)
GetCurrent().Update(deltaTime)
End Method
End Type
Type TSpriteFrameAnimation
Field name:string
'how many times animation should repeat until finished
Field repeatTimes:int = 0
'frame of sprite/image
Field currentImageFrame:int = 0
Field currentSpriteName:string = ""
'position in frames-array
Field currentFrame:int = 0
Field frames:int[]
Field spriteNames:string[]
'duration for each frame
Field framesTime:float[]
'stay with currentFrame or cycle through frames?
Field paused:Int = FALSE
Field frameTimer:float = null
Field randomness:float = 0
Field flags:int = 0
'use this flag to use the default GetDelta() instead of the given
'one -> ignores the WorldSpeedFactor given by the sprite
Const FLAG_IGNORE_DELTATIME_PARAM:int = 1
Function Create:TSpriteFrameAnimation(name:string, framesArray:int[][], repeatTimes:int=0, paused:int=0, randomness:Int = 0)
local obj:TSpriteFrameAnimation = new TSpriteFrameAnimation
local framecount:int = len( framesArray )
obj.name = name
obj.frames = obj.frames[..framecount] 'extend
obj.framesTime = obj.framesTime[..framecount] 'extend
obj.randomness = 0.001 * randomness 'ms to second
For local i:int = 0 until framecount
obj.frames[i] = framesArray[i][0]
obj.framesTime[i] = float(framesArray[i][1]) * 0.001
Next
obj.repeatTimes = repeatTimes
obj.paused = paused
return obj
End Function
Function CreateWithSpriteNames:TSpriteFrameAnimation(name:string, spriteNames:string[], frameTimes:int[], repeatTimes:int=0, paused:int=0, randomness:Int = 0)
local obj:TSpriteFrameAnimation = new TSpriteFrameAnimation
local framecount:int = frameTimes.length
obj.name = name
obj.frames = obj.frames[..framecount] 'extend
obj.spriteNames = obj.spriteNames[..framecount] 'extend
obj.framesTime = obj.framesTime[..framecount] 'extend
obj.randomness = 0.001 * randomness 'ms to second
For local i:int = 0 until framecount
obj.spriteNames[i] = spriteNames[i]
obj.framesTime[i] = float(frameTimes[i]) * 0.001
Next
obj.repeatTimes = repeatTimes
obj.paused = paused
return obj
End Function
Function CreateSimple:TSpriteFrameAnimation(name:string, frameAmount:int, frameTime:int, repeatTimes:int=0, paused:int=0, randomness:Int = 0)
local f:int[][]
For local i:int = 0 until frameAmount
f :+ [[i,frameTime]]
Next
return Create(name, f, repeatTimes, paused, randomness)
End Function
Function CreateSimpleWithSpriteNames:TSpriteFrameAnimation(name:string, spriteNames:string[], frameTime:int, repeatTimes:int=0, paused:int=0, randomness:Int = 0)
local f:int[]
For local i:int = 0 until spriteNames.length
f :+ [frameTime]
Next
return CreateWithSpriteNames(name, spriteNames, f, repeatTimes, paused, randomness)
End Function
Method InitFromData:TSpriteFrameAnimation(data:TData)
name = data.GetString("name")
repeatTimes = data.GetInt("repeatTimes", -1) 'default to "loop"
currentImageFrame = data.GetInt("currentImageFrame")
currentFrame = data.GetInt("currentFrame")
currentSpriteName = data.GetString("currentSpriteName")
paused = data.GetInt("paused")
frameTimer = data.GetFloat("frameTimer")
randomness = data.GetFloat("randomness")
flags = data.GetInt("flags")
For local s:string = EachIn data.GetString("frames").Split("::")
frames :+ [int(s)]
Next
For local s:string = EachIn data.GetString("spriteNames").Split("::")
spriteNames :+ [s]
Next
For local s:string = EachIn data.GetString("framesTime").Split("::")
framesTime :+ [float(s)]
Next
'if not enough framesTime were defined, just reuse the last
'time for the missing ones
if frames.length > 0
For local i:int = framesTime.length until frames.length
framesTime :+ [ framesTime[framesTime.length-1] ]
Next
endif
return self
End Method
Method Copy:TSpriteFrameAnimation()
local c:TSpriteFrameAnimation = new TSpriteFrameAnimation
c.name = name
c.repeatTimes = repeatTimes
c.currentImageFrame = currentImageFrame
c.currentFrame = currentFrame
c.currentSpriteName = currentSpriteName
c.frames = frames[..]
if spriteNames
c.spriteNames = spriteNames[..]
else
c.spriteNames = null
endif
c.framesTime = framesTime[..]
c.paused = paused
c.frameTimer = frameTimer
c.randomness = randomness
return c
End Method
Method SetFlag(flag:Int, enable:Int=True)
If enable
flags :| flag
Else
flags :& ~flag
EndIf
End Method
Method HasFlag:Int(flag:Int)
Return (flags & flag) <> 0
End Method
Function GetDeltaTime:Float()
return GetDeltaTimer().GetDelta()
End Function
Method Update:int(deltaTime:Float = -1)
'skip update if only 1 frame is set
'skip if paused
If paused or frames.length <= 1 then return 0
'use given or default deltaTime?
if deltaTime < 0 or HasFlag(FLAG_IGNORE_DELTATIME_PARAM)
deltaTime = GetDeltaTime()
endif
if frameTimer = null then ResetFrameTimer()
frameTimer :- deltaTime
'skip frames if delta is bigger than frame time
'time for next frame
While frameTimer <= 0
local oldFrameTimer:Float = frameTimer
local nextPos:int = currentFrame + 1
'increase current frameposition but only if frame is set
'resets frametimer too
setCurrentFrame(nextPos)
'reached end? (use nextPos as setCurrentFramePos already limits value)
If nextPos >= len(frames)
If repeatTimes = 0
Pause() 'stop animation
exit 'exit the while loop
Else
setCurrentFrame(0)
repeatTimes :-1
EndIf
EndIf
'add back what was left before
frameTimer = oldFrameTimer + frameTimer
Wend
End Method
Method Reset()
setCurrentFrame(0)
End Method
Method ResetFrameTimer()
frameTimer = framesTime[currentFrame] + 0.001*Rand(Int(-1000*randomness), Int(1000*randomness))
End Method
Method GetFrameCount:int()
return len(frames)
End Method
Method GetCurrentImageFrame:int()
return currentImageFrame
End Method
Method SetCurrentImageFrame(frame:int)
currentImageFrame = frame
ResetFrameTimer()
End Method
Method GetCurrentFrame:int()
return currentFrame
End Method
Method SetCurrentFrame(framePos:int)
currentFrame = Max( Min(framePos, len(frames) - 1), 0)
'set the image frame of thhe animation frame
setCurrentImageFrame( frames[currentFrame] )
if spriteNames and spriteNames.length > currentFrame
setCurrentSpriteName( spriteNames[currentFrame] )
endif
End Method
Method SetCurrentSpriteName(name:string)
currentSpriteName = name
ResetFrameTimer()
End Method
Method GetCurrentSpriteName:string()
return currentSpriteName
End Method
Method isPaused:Int()
return paused
End Method
Method isFinished:Int()
return paused AND (currentFrame >= len(frames)-1)
End Method
Method Playback()
paused = 0
End Method
Method Pause()
paused = 1
End Method
End Type