bevy 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Cargo.lock +4279 -0
- data/Cargo.toml +36 -0
- data/README.md +226 -0
- data/crates/bevy/Cargo.toml +52 -0
- data/crates/bevy/src/app.rs +43 -0
- data/crates/bevy/src/component.rs +111 -0
- data/crates/bevy/src/entity.rs +30 -0
- data/crates/bevy/src/error.rs +32 -0
- data/crates/bevy/src/event.rs +190 -0
- data/crates/bevy/src/input_bridge.rs +300 -0
- data/crates/bevy/src/lib.rs +42 -0
- data/crates/bevy/src/mesh_renderer.rs +328 -0
- data/crates/bevy/src/query.rs +53 -0
- data/crates/bevy/src/render_app.rs +689 -0
- data/crates/bevy/src/resource.rs +28 -0
- data/crates/bevy/src/schedule.rs +186 -0
- data/crates/bevy/src/sprite_renderer.rs +355 -0
- data/crates/bevy/src/system.rs +44 -0
- data/crates/bevy/src/text_renderer.rs +258 -0
- data/crates/bevy/src/types/color.rs +114 -0
- data/crates/bevy/src/types/dynamic.rs +131 -0
- data/crates/bevy/src/types/math.rs +260 -0
- data/crates/bevy/src/types/mod.rs +9 -0
- data/crates/bevy/src/types/transform.rs +166 -0
- data/crates/bevy/src/world.rs +163 -0
- data/crates/bevy_ruby_render/Cargo.toml +22 -0
- data/crates/bevy_ruby_render/src/asset.rs +360 -0
- data/crates/bevy_ruby_render/src/audio.rs +511 -0
- data/crates/bevy_ruby_render/src/camera.rs +365 -0
- data/crates/bevy_ruby_render/src/gamepad.rs +398 -0
- data/crates/bevy_ruby_render/src/lib.rs +26 -0
- data/crates/bevy_ruby_render/src/material.rs +310 -0
- data/crates/bevy_ruby_render/src/mesh.rs +491 -0
- data/crates/bevy_ruby_render/src/sprite.rs +289 -0
- data/ext/bevy/Cargo.toml +20 -0
- data/ext/bevy/extconf.rb +6 -0
- data/ext/bevy/src/conversions.rs +137 -0
- data/ext/bevy/src/lib.rs +29 -0
- data/ext/bevy/src/ruby_app.rs +65 -0
- data/ext/bevy/src/ruby_color.rs +149 -0
- data/ext/bevy/src/ruby_component.rs +189 -0
- data/ext/bevy/src/ruby_entity.rs +33 -0
- data/ext/bevy/src/ruby_math.rs +384 -0
- data/ext/bevy/src/ruby_query.rs +64 -0
- data/ext/bevy/src/ruby_render_app.rs +779 -0
- data/ext/bevy/src/ruby_system.rs +122 -0
- data/ext/bevy/src/ruby_world.rs +107 -0
- data/lib/bevy/animation.rb +597 -0
- data/lib/bevy/app.rb +675 -0
- data/lib/bevy/asset.rb +613 -0
- data/lib/bevy/audio.rb +545 -0
- data/lib/bevy/audio_effects.rb +224 -0
- data/lib/bevy/camera.rb +412 -0
- data/lib/bevy/component.rb +91 -0
- data/lib/bevy/diagnostics.rb +227 -0
- data/lib/bevy/ecs_advanced.rb +296 -0
- data/lib/bevy/event.rb +199 -0
- data/lib/bevy/gizmos.rb +158 -0
- data/lib/bevy/gltf.rb +227 -0
- data/lib/bevy/hierarchy.rb +444 -0
- data/lib/bevy/input.rb +514 -0
- data/lib/bevy/lighting.rb +369 -0
- data/lib/bevy/material.rb +248 -0
- data/lib/bevy/mesh.rb +257 -0
- data/lib/bevy/navigation.rb +344 -0
- data/lib/bevy/networking.rb +335 -0
- data/lib/bevy/particle.rb +337 -0
- data/lib/bevy/physics.rb +396 -0
- data/lib/bevy/plugins/default_plugins.rb +34 -0
- data/lib/bevy/plugins/input_plugin.rb +49 -0
- data/lib/bevy/reflect.rb +361 -0
- data/lib/bevy/render_graph.rb +210 -0
- data/lib/bevy/resource.rb +185 -0
- data/lib/bevy/scene.rb +254 -0
- data/lib/bevy/shader.rb +319 -0
- data/lib/bevy/shape.rb +195 -0
- data/lib/bevy/skeletal.rb +248 -0
- data/lib/bevy/sprite.rb +152 -0
- data/lib/bevy/sprite_sheet.rb +444 -0
- data/lib/bevy/state.rb +277 -0
- data/lib/bevy/system.rb +206 -0
- data/lib/bevy/text.rb +99 -0
- data/lib/bevy/text_advanced.rb +455 -0
- data/lib/bevy/timer.rb +147 -0
- data/lib/bevy/transform.rb +158 -0
- data/lib/bevy/ui.rb +454 -0
- data/lib/bevy/ui_advanced.rb +568 -0
- data/lib/bevy/version.rb +5 -0
- data/lib/bevy/visibility.rb +250 -0
- data/lib/bevy/window.rb +302 -0
- data/lib/bevy.rb +390 -0
- metadata +150 -0
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bevy
|
|
4
|
+
module Easing
|
|
5
|
+
def self.linear(t)
|
|
6
|
+
t
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.ease_in_quad(t)
|
|
10
|
+
t * t
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.ease_out_quad(t)
|
|
14
|
+
1.0 - (1.0 - t) * (1.0 - t)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.ease_in_out_quad(t)
|
|
18
|
+
t < 0.5 ? 2.0 * t * t : 1.0 - ((-2.0 * t + 2.0)**2) / 2.0
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.ease_in_cubic(t)
|
|
22
|
+
t * t * t
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.ease_out_cubic(t)
|
|
26
|
+
1.0 - ((1.0 - t)**3)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.ease_in_out_cubic(t)
|
|
30
|
+
t < 0.5 ? 4.0 * t * t * t : 1.0 - ((-2.0 * t + 2.0)**3) / 2.0
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.ease_in_sine(t)
|
|
34
|
+
1.0 - Math.cos((t * Math::PI) / 2.0)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.ease_out_sine(t)
|
|
38
|
+
Math.sin((t * Math::PI) / 2.0)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.ease_in_out_sine(t)
|
|
42
|
+
-(Math.cos(Math::PI * t) - 1.0) / 2.0
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.ease_in_expo(t)
|
|
46
|
+
t == 0.0 ? 0.0 : 2.0**(10.0 * t - 10.0)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.ease_out_expo(t)
|
|
50
|
+
t == 1.0 ? 1.0 : 1.0 - 2.0**(-10.0 * t)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.ease_in_out_expo(t)
|
|
54
|
+
return 0.0 if t == 0.0
|
|
55
|
+
return 1.0 if t == 1.0
|
|
56
|
+
|
|
57
|
+
if t < 0.5
|
|
58
|
+
2.0**(20.0 * t - 10.0) / 2.0
|
|
59
|
+
else
|
|
60
|
+
(2.0 - 2.0**(-20.0 * t + 10.0)) / 2.0
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.ease_in_back(t)
|
|
65
|
+
c1 = 1.70158
|
|
66
|
+
c3 = c1 + 1.0
|
|
67
|
+
c3 * t * t * t - c1 * t * t
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def self.ease_out_back(t)
|
|
71
|
+
c1 = 1.70158
|
|
72
|
+
c3 = c1 + 1.0
|
|
73
|
+
1.0 + c3 * ((t - 1.0)**3) + c1 * ((t - 1.0)**2)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def self.ease_in_out_back(t)
|
|
77
|
+
c1 = 1.70158
|
|
78
|
+
c2 = c1 * 1.525
|
|
79
|
+
if t < 0.5
|
|
80
|
+
((2.0 * t)**2 * ((c2 + 1.0) * 2.0 * t - c2)) / 2.0
|
|
81
|
+
else
|
|
82
|
+
((2.0 * t - 2.0)**2 * ((c2 + 1.0) * (t * 2.0 - 2.0) + c2) + 2.0) / 2.0
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def self.ease_in_elastic(t)
|
|
87
|
+
return 0.0 if t == 0.0
|
|
88
|
+
return 1.0 if t == 1.0
|
|
89
|
+
|
|
90
|
+
c4 = (2.0 * Math::PI) / 3.0
|
|
91
|
+
-(2.0**(10.0 * t - 10.0)) * Math.sin((t * 10.0 - 10.75) * c4)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def self.ease_out_elastic(t)
|
|
95
|
+
return 0.0 if t == 0.0
|
|
96
|
+
return 1.0 if t == 1.0
|
|
97
|
+
|
|
98
|
+
c4 = (2.0 * Math::PI) / 3.0
|
|
99
|
+
2.0**(-10.0 * t) * Math.sin((t * 10.0 - 0.75) * c4) + 1.0
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def self.ease_in_bounce(t)
|
|
103
|
+
1.0 - ease_out_bounce(1.0 - t)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def self.ease_out_bounce(t)
|
|
107
|
+
n1 = 7.5625
|
|
108
|
+
d1 = 2.75
|
|
109
|
+
|
|
110
|
+
if t < 1.0 / d1
|
|
111
|
+
n1 * t * t
|
|
112
|
+
elsif t < 2.0 / d1
|
|
113
|
+
t -= 1.5 / d1
|
|
114
|
+
n1 * t * t + 0.75
|
|
115
|
+
elsif t < 2.5 / d1
|
|
116
|
+
t -= 2.25 / d1
|
|
117
|
+
n1 * t * t + 0.9375
|
|
118
|
+
else
|
|
119
|
+
t -= 2.625 / d1
|
|
120
|
+
n1 * t * t + 0.984375
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def self.ease_in_out_bounce(t)
|
|
125
|
+
if t < 0.5
|
|
126
|
+
(1.0 - ease_out_bounce(1.0 - 2.0 * t)) / 2.0
|
|
127
|
+
else
|
|
128
|
+
(1.0 + ease_out_bounce(2.0 * t - 1.0)) / 2.0
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def self.apply(easing, t)
|
|
133
|
+
case easing
|
|
134
|
+
when :linear then linear(t)
|
|
135
|
+
when :ease_in_quad then ease_in_quad(t)
|
|
136
|
+
when :ease_out_quad then ease_out_quad(t)
|
|
137
|
+
when :ease_in_out_quad then ease_in_out_quad(t)
|
|
138
|
+
when :ease_in_cubic then ease_in_cubic(t)
|
|
139
|
+
when :ease_out_cubic then ease_out_cubic(t)
|
|
140
|
+
when :ease_in_out_cubic then ease_in_out_cubic(t)
|
|
141
|
+
when :ease_in_sine then ease_in_sine(t)
|
|
142
|
+
when :ease_out_sine then ease_out_sine(t)
|
|
143
|
+
when :ease_in_out_sine then ease_in_out_sine(t)
|
|
144
|
+
when :ease_in_expo then ease_in_expo(t)
|
|
145
|
+
when :ease_out_expo then ease_out_expo(t)
|
|
146
|
+
when :ease_in_out_expo then ease_in_out_expo(t)
|
|
147
|
+
when :ease_in_back then ease_in_back(t)
|
|
148
|
+
when :ease_out_back then ease_out_back(t)
|
|
149
|
+
when :ease_in_out_back then ease_in_out_back(t)
|
|
150
|
+
when :ease_in_elastic then ease_in_elastic(t)
|
|
151
|
+
when :ease_out_elastic then ease_out_elastic(t)
|
|
152
|
+
when :ease_in_bounce then ease_in_bounce(t)
|
|
153
|
+
when :ease_out_bounce then ease_out_bounce(t)
|
|
154
|
+
when :ease_in_out_bounce then ease_in_out_bounce(t)
|
|
155
|
+
when Proc then easing.call(t)
|
|
156
|
+
else linear(t)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
class Keyframe
|
|
162
|
+
attr_reader :time, :value, :easing
|
|
163
|
+
|
|
164
|
+
def initialize(time, value, easing: :linear)
|
|
165
|
+
@time = time.to_f
|
|
166
|
+
@value = value
|
|
167
|
+
@easing = easing
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def interpolate_to(other, t)
|
|
171
|
+
eased_t = Easing.apply(@easing, t)
|
|
172
|
+
|
|
173
|
+
case @value
|
|
174
|
+
when Numeric
|
|
175
|
+
@value + (other.value - @value) * eased_t
|
|
176
|
+
when Vec2
|
|
177
|
+
Vec2.new(
|
|
178
|
+
@value.x + (other.value.x - @value.x) * eased_t,
|
|
179
|
+
@value.y + (other.value.y - @value.y) * eased_t
|
|
180
|
+
)
|
|
181
|
+
when Vec3
|
|
182
|
+
Vec3.new(
|
|
183
|
+
@value.x + (other.value.x - @value.x) * eased_t,
|
|
184
|
+
@value.y + (other.value.y - @value.y) * eased_t,
|
|
185
|
+
@value.z + (other.value.z - @value.z) * eased_t
|
|
186
|
+
)
|
|
187
|
+
when Color
|
|
188
|
+
Color.rgba(
|
|
189
|
+
@value.r + (other.value.r - @value.r) * eased_t,
|
|
190
|
+
@value.g + (other.value.g - @value.g) * eased_t,
|
|
191
|
+
@value.b + (other.value.b - @value.b) * eased_t,
|
|
192
|
+
@value.a + (other.value.a - @value.a) * eased_t
|
|
193
|
+
)
|
|
194
|
+
when Array
|
|
195
|
+
@value.zip(other.value).map do |a, b|
|
|
196
|
+
a + (b - a) * eased_t
|
|
197
|
+
end
|
|
198
|
+
when Hash
|
|
199
|
+
@value.keys.each_with_object({}) do |key, result|
|
|
200
|
+
a = @value[key]
|
|
201
|
+
b = other.value[key]
|
|
202
|
+
result[key] = a + (b - a) * eased_t
|
|
203
|
+
end
|
|
204
|
+
else
|
|
205
|
+
t < 1.0 ? @value : other.value
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
class AnimationTrack
|
|
211
|
+
attr_reader :property, :keyframes
|
|
212
|
+
|
|
213
|
+
def initialize(property)
|
|
214
|
+
@property = property
|
|
215
|
+
@keyframes = []
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def add_keyframe(time, value, easing: :linear)
|
|
219
|
+
@keyframes << Keyframe.new(time, value, easing: easing)
|
|
220
|
+
@keyframes.sort_by!(&:time)
|
|
221
|
+
self
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def duration
|
|
225
|
+
return 0.0 if @keyframes.empty?
|
|
226
|
+
|
|
227
|
+
@keyframes.last.time
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def sample(time)
|
|
231
|
+
return nil if @keyframes.empty?
|
|
232
|
+
return @keyframes.first.value if time <= @keyframes.first.time
|
|
233
|
+
return @keyframes.last.value if time >= @keyframes.last.time
|
|
234
|
+
|
|
235
|
+
prev_keyframe = nil
|
|
236
|
+
next_keyframe = nil
|
|
237
|
+
|
|
238
|
+
@keyframes.each_cons(2) do |a, b|
|
|
239
|
+
if time >= a.time && time < b.time
|
|
240
|
+
prev_keyframe = a
|
|
241
|
+
next_keyframe = b
|
|
242
|
+
break
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
return @keyframes.last.value unless prev_keyframe && next_keyframe
|
|
247
|
+
|
|
248
|
+
local_t = (time - prev_keyframe.time) / (next_keyframe.time - prev_keyframe.time)
|
|
249
|
+
prev_keyframe.interpolate_to(next_keyframe, local_t)
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
class AnimationClip
|
|
254
|
+
attr_reader :name, :tracks, :repeat_mode
|
|
255
|
+
|
|
256
|
+
def initialize(name, repeat_mode: :once)
|
|
257
|
+
@name = name
|
|
258
|
+
@tracks = {}
|
|
259
|
+
@repeat_mode = repeat_mode
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def add_track(property)
|
|
263
|
+
@tracks[property] = AnimationTrack.new(property)
|
|
264
|
+
@tracks[property]
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def get_track(property)
|
|
268
|
+
@tracks[property]
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def duration
|
|
272
|
+
@tracks.values.map(&:duration).max || 0.0
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def sample(time)
|
|
276
|
+
@tracks.transform_values { |track| track.sample(time) }
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def sample_property(property, time)
|
|
280
|
+
track = @tracks[property]
|
|
281
|
+
track&.sample(time)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def type_name
|
|
285
|
+
'AnimationClip'
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
class AnimationPlayer
|
|
290
|
+
attr_reader :current_clip, :elapsed, :speed, :paused
|
|
291
|
+
|
|
292
|
+
def initialize
|
|
293
|
+
@clips = {}
|
|
294
|
+
@current_clip = nil
|
|
295
|
+
@elapsed = 0.0
|
|
296
|
+
@speed = 1.0
|
|
297
|
+
@paused = false
|
|
298
|
+
@on_finish_callbacks = []
|
|
299
|
+
@on_loop_callbacks = []
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def add_clip(clip)
|
|
303
|
+
@clips[clip.name] = clip
|
|
304
|
+
self
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def play(clip_name, restart: false)
|
|
308
|
+
if @current_clip != clip_name || restart
|
|
309
|
+
@current_clip = clip_name
|
|
310
|
+
@elapsed = 0.0
|
|
311
|
+
end
|
|
312
|
+
@paused = false
|
|
313
|
+
self
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def pause
|
|
317
|
+
@paused = true
|
|
318
|
+
self
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def resume
|
|
322
|
+
@paused = false
|
|
323
|
+
self
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def stop
|
|
327
|
+
@current_clip = nil
|
|
328
|
+
@elapsed = 0.0
|
|
329
|
+
@paused = false
|
|
330
|
+
self
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def set_speed(speed)
|
|
334
|
+
@speed = speed
|
|
335
|
+
self
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def seek(time)
|
|
339
|
+
@elapsed = time.clamp(0.0, duration)
|
|
340
|
+
self
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
def on_finish(&block)
|
|
344
|
+
@on_finish_callbacks << block
|
|
345
|
+
self
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def on_loop(&block)
|
|
349
|
+
@on_loop_callbacks << block
|
|
350
|
+
self
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def update(delta)
|
|
354
|
+
return unless @current_clip && !@paused
|
|
355
|
+
|
|
356
|
+
clip = @clips[@current_clip]
|
|
357
|
+
return unless clip
|
|
358
|
+
|
|
359
|
+
@elapsed += delta * @speed
|
|
360
|
+
clip_duration = clip.duration
|
|
361
|
+
|
|
362
|
+
return if clip_duration <= 0.0
|
|
363
|
+
|
|
364
|
+
case clip.repeat_mode
|
|
365
|
+
when :once
|
|
366
|
+
if @elapsed >= clip_duration
|
|
367
|
+
@elapsed = clip_duration
|
|
368
|
+
@on_finish_callbacks.each(&:call)
|
|
369
|
+
@current_clip = nil
|
|
370
|
+
end
|
|
371
|
+
when :loop
|
|
372
|
+
while @elapsed >= clip_duration
|
|
373
|
+
@elapsed -= clip_duration
|
|
374
|
+
@on_loop_callbacks.each(&:call)
|
|
375
|
+
end
|
|
376
|
+
when :ping_pong
|
|
377
|
+
cycle = (@elapsed / clip_duration).to_i
|
|
378
|
+
local_t = @elapsed % clip_duration
|
|
379
|
+
@elapsed = cycle.odd? ? clip_duration - local_t : local_t
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
def sample
|
|
384
|
+
return {} unless @current_clip
|
|
385
|
+
|
|
386
|
+
clip = @clips[@current_clip]
|
|
387
|
+
return {} unless clip
|
|
388
|
+
|
|
389
|
+
clip.sample(@elapsed)
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
def sample_property(property)
|
|
393
|
+
return nil unless @current_clip
|
|
394
|
+
|
|
395
|
+
clip = @clips[@current_clip]
|
|
396
|
+
return nil unless clip
|
|
397
|
+
|
|
398
|
+
clip.sample_property(property, @elapsed)
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def duration
|
|
402
|
+
return 0.0 unless @current_clip
|
|
403
|
+
|
|
404
|
+
@clips[@current_clip]&.duration || 0.0
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
def progress
|
|
408
|
+
d = duration
|
|
409
|
+
return 0.0 if d <= 0.0
|
|
410
|
+
|
|
411
|
+
@elapsed / d
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
def playing?
|
|
415
|
+
@current_clip && !@paused
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
def finished?
|
|
419
|
+
@current_clip.nil? && @elapsed > 0.0
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
def type_name
|
|
423
|
+
'AnimationPlayer'
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
class Tween
|
|
428
|
+
attr_reader :from, :to, :duration, :elapsed, :easing, :repeat_mode
|
|
429
|
+
|
|
430
|
+
def initialize(from:, to:, duration:, easing: :linear, repeat_mode: :once, delay: 0.0)
|
|
431
|
+
@from = from
|
|
432
|
+
@to = to
|
|
433
|
+
@duration = duration.to_f
|
|
434
|
+
@easing = easing
|
|
435
|
+
@repeat_mode = repeat_mode
|
|
436
|
+
@delay = delay.to_f
|
|
437
|
+
@elapsed = 0.0
|
|
438
|
+
@started = false
|
|
439
|
+
@finished = false
|
|
440
|
+
@on_update_callbacks = []
|
|
441
|
+
@on_complete_callbacks = []
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
def update(delta)
|
|
445
|
+
return if @finished
|
|
446
|
+
|
|
447
|
+
if !@started
|
|
448
|
+
@delay -= delta
|
|
449
|
+
if @delay <= 0.0
|
|
450
|
+
@started = true
|
|
451
|
+
@elapsed = -@delay
|
|
452
|
+
else
|
|
453
|
+
return
|
|
454
|
+
end
|
|
455
|
+
else
|
|
456
|
+
@elapsed += delta
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
if @elapsed >= @duration
|
|
460
|
+
case @repeat_mode
|
|
461
|
+
when :once
|
|
462
|
+
@elapsed = @duration
|
|
463
|
+
@finished = true
|
|
464
|
+
@on_complete_callbacks.each(&:call)
|
|
465
|
+
when :loop
|
|
466
|
+
@elapsed = @elapsed % @duration
|
|
467
|
+
when :ping_pong
|
|
468
|
+
cycle = (@elapsed / @duration).to_i
|
|
469
|
+
local_t = @elapsed % @duration
|
|
470
|
+
@elapsed = cycle.odd? ? @duration - local_t : local_t
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
@on_update_callbacks.each { |cb| cb.call(current_value) }
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
def current_value
|
|
478
|
+
t = progress
|
|
479
|
+
Keyframe.new(0, @from, easing: @easing).interpolate_to(Keyframe.new(1, @to), t)
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
def progress
|
|
483
|
+
return 0.0 if @duration <= 0.0
|
|
484
|
+
|
|
485
|
+
(@elapsed / @duration).clamp(0.0, 1.0)
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
def finished?
|
|
489
|
+
@finished
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
def started?
|
|
493
|
+
@started
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
def reset
|
|
497
|
+
@elapsed = 0.0
|
|
498
|
+
@started = false
|
|
499
|
+
@finished = false
|
|
500
|
+
self
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
def on_update(&block)
|
|
504
|
+
@on_update_callbacks << block
|
|
505
|
+
self
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
def on_complete(&block)
|
|
509
|
+
@on_complete_callbacks << block
|
|
510
|
+
self
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
def type_name
|
|
514
|
+
'Tween'
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
class TweenSequence
|
|
519
|
+
def initialize
|
|
520
|
+
@tweens = []
|
|
521
|
+
@current_index = 0
|
|
522
|
+
@finished = false
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
def add(tween)
|
|
526
|
+
@tweens << tween
|
|
527
|
+
self
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
def update(delta)
|
|
531
|
+
return if @finished || @tweens.empty?
|
|
532
|
+
|
|
533
|
+
current_tween = @tweens[@current_index]
|
|
534
|
+
current_tween.update(delta)
|
|
535
|
+
|
|
536
|
+
if current_tween.finished?
|
|
537
|
+
@current_index += 1
|
|
538
|
+
if @current_index >= @tweens.size
|
|
539
|
+
@finished = true
|
|
540
|
+
end
|
|
541
|
+
end
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
def current_value
|
|
545
|
+
return nil if @tweens.empty?
|
|
546
|
+
|
|
547
|
+
@tweens[@current_index]&.current_value
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
def finished?
|
|
551
|
+
@finished
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
def reset
|
|
555
|
+
@tweens.each(&:reset)
|
|
556
|
+
@current_index = 0
|
|
557
|
+
@finished = false
|
|
558
|
+
self
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
def type_name
|
|
562
|
+
'TweenSequence'
|
|
563
|
+
end
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
class TweenGroup
|
|
567
|
+
def initialize
|
|
568
|
+
@tweens = []
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
def add(tween)
|
|
572
|
+
@tweens << tween
|
|
573
|
+
self
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
def update(delta)
|
|
577
|
+
@tweens.each { |t| t.update(delta) }
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
def values
|
|
581
|
+
@tweens.map(&:current_value)
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
def finished?
|
|
585
|
+
@tweens.all?(&:finished?)
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
def reset
|
|
589
|
+
@tweens.each(&:reset)
|
|
590
|
+
self
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
def type_name
|
|
594
|
+
'TweenGroup'
|
|
595
|
+
end
|
|
596
|
+
end
|
|
597
|
+
end
|