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,455 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bevy
|
|
4
|
+
class Font
|
|
5
|
+
attr_reader :path, :data
|
|
6
|
+
|
|
7
|
+
def initialize(path: nil, data: nil)
|
|
8
|
+
@path = path
|
|
9
|
+
@data = data
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def loaded?
|
|
13
|
+
!@data.nil?
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def type_name
|
|
17
|
+
'Font'
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class FontAtlas
|
|
22
|
+
attr_reader :font, :size, :glyphs
|
|
23
|
+
|
|
24
|
+
def initialize(font:, size: 16.0)
|
|
25
|
+
@font = font
|
|
26
|
+
@size = size.to_f
|
|
27
|
+
@glyphs = {}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def add_glyph(char, glyph_info)
|
|
31
|
+
@glyphs[char] = glyph_info
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def get_glyph(char)
|
|
35
|
+
@glyphs[char]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def has_glyph?(char)
|
|
39
|
+
@glyphs.key?(char)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def type_name
|
|
43
|
+
'FontAtlas'
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class GlyphInfo
|
|
48
|
+
attr_reader :char, :rect, :bearing, :advance
|
|
49
|
+
|
|
50
|
+
def initialize(char:, rect:, bearing:, advance:)
|
|
51
|
+
@char = char
|
|
52
|
+
@rect = rect
|
|
53
|
+
@bearing = bearing
|
|
54
|
+
@advance = advance.to_f
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def type_name
|
|
58
|
+
'GlyphInfo'
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class TextStyle
|
|
63
|
+
attr_accessor :font, :font_size, :color
|
|
64
|
+
|
|
65
|
+
def initialize(font: nil, font_size: 16.0, color: nil)
|
|
66
|
+
@font = font
|
|
67
|
+
@font_size = font_size.to_f
|
|
68
|
+
@color = color || Color.white
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def with_font(font)
|
|
72
|
+
self.class.new(font: font, font_size: @font_size, color: @color)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def with_font_size(size)
|
|
76
|
+
self.class.new(font: @font, font_size: size, color: @color)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def with_color(color)
|
|
80
|
+
self.class.new(font: @font, font_size: @font_size, color: color)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def type_name
|
|
84
|
+
'TextStyle'
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
module JustifyText
|
|
89
|
+
LEFT = :left
|
|
90
|
+
CENTER = :center
|
|
91
|
+
RIGHT = :right
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
class Text
|
|
95
|
+
attr_accessor :sections, :justify, :linebreak_behavior
|
|
96
|
+
|
|
97
|
+
def initialize(value = '', style: nil)
|
|
98
|
+
if value.is_a?(String)
|
|
99
|
+
@sections = [TextSection.new(value: value, style: style || TextStyle.new)]
|
|
100
|
+
else
|
|
101
|
+
@sections = value.is_a?(Array) ? value : [value]
|
|
102
|
+
end
|
|
103
|
+
@justify = JustifyText::LEFT
|
|
104
|
+
@linebreak_behavior = :word_boundary
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def self.from_section(section)
|
|
108
|
+
new([section])
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def self.from_sections(sections)
|
|
112
|
+
new(sections)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def add_section(section)
|
|
116
|
+
@sections << section
|
|
117
|
+
self
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def clear
|
|
121
|
+
@sections = []
|
|
122
|
+
self
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def full_text
|
|
126
|
+
@sections.map(&:value).join
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def with_justify(justify)
|
|
130
|
+
@justify = justify
|
|
131
|
+
self
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def type_name
|
|
135
|
+
'Text'
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
class TextSection
|
|
140
|
+
attr_accessor :value, :style
|
|
141
|
+
|
|
142
|
+
def initialize(value: '', style: nil)
|
|
143
|
+
@value = value
|
|
144
|
+
@style = style || TextStyle.new
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def with_style(style)
|
|
148
|
+
self.class.new(value: @value, style: style)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def type_name
|
|
152
|
+
'TextSection'
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
class TextLayoutInfo
|
|
157
|
+
attr_accessor :glyphs, :size
|
|
158
|
+
|
|
159
|
+
def initialize
|
|
160
|
+
@glyphs = []
|
|
161
|
+
@size = Vec2.zero
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def type_name
|
|
165
|
+
'TextLayoutInfo'
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
class TextFlags
|
|
170
|
+
attr_accessor :needs_recompute
|
|
171
|
+
|
|
172
|
+
def initialize
|
|
173
|
+
@needs_recompute = true
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def type_name
|
|
177
|
+
'TextFlags'
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
class CalculatedSize
|
|
182
|
+
attr_accessor :size
|
|
183
|
+
|
|
184
|
+
def initialize(size: nil)
|
|
185
|
+
@size = size || Vec2.zero
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def type_name
|
|
189
|
+
'CalculatedSize'
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
class ZIndex
|
|
194
|
+
attr_accessor :value
|
|
195
|
+
|
|
196
|
+
GLOBAL = :global
|
|
197
|
+
LOCAL = :local
|
|
198
|
+
|
|
199
|
+
def initialize(value: 0, mode: LOCAL)
|
|
200
|
+
@value = value
|
|
201
|
+
@mode = mode
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def global?
|
|
205
|
+
@mode == GLOBAL
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def local?
|
|
209
|
+
@mode == LOCAL
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def type_name
|
|
213
|
+
'ZIndex'
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
module FocusPolicy
|
|
218
|
+
NONE = :none
|
|
219
|
+
BLOCK = :block
|
|
220
|
+
PASS = :pass
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
class RichText
|
|
224
|
+
attr_reader :sections
|
|
225
|
+
|
|
226
|
+
def initialize
|
|
227
|
+
@sections = []
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def push(text, style: nil)
|
|
231
|
+
@sections << RichTextSection.new(text: text, style: style || TextStyle.new)
|
|
232
|
+
self
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def bold(text, base_style: nil)
|
|
236
|
+
style = (base_style || TextStyle.new).dup
|
|
237
|
+
push(text, style: RichTextStyle.new(base: style, weight: :bold))
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def italic(text, base_style: nil)
|
|
241
|
+
style = (base_style || TextStyle.new).dup
|
|
242
|
+
push(text, style: RichTextStyle.new(base: style, slant: :italic))
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def colored(text, color, base_style: nil)
|
|
246
|
+
style = (base_style || TextStyle.new).with_color(color)
|
|
247
|
+
push(text, style: style)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def sized(text, size, base_style: nil)
|
|
251
|
+
style = (base_style || TextStyle.new).with_font_size(size)
|
|
252
|
+
push(text, style: style)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def clear
|
|
256
|
+
@sections = []
|
|
257
|
+
self
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def to_text
|
|
261
|
+
Text.from_sections(@sections.map { |s| s.to_text_section })
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def type_name
|
|
265
|
+
'RichText'
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
class RichTextSection
|
|
270
|
+
attr_reader :text, :style
|
|
271
|
+
|
|
272
|
+
def initialize(text:, style:)
|
|
273
|
+
@text = text
|
|
274
|
+
@style = style
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def to_text_section
|
|
278
|
+
TextSection.new(value: @text, style: @style.respond_to?(:base) ? @style.base : @style)
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def type_name
|
|
282
|
+
'RichTextSection'
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
class RichTextStyle
|
|
287
|
+
attr_reader :base, :weight, :slant, :underline, :strikethrough
|
|
288
|
+
|
|
289
|
+
WEIGHT_NORMAL = :normal
|
|
290
|
+
WEIGHT_BOLD = :bold
|
|
291
|
+
WEIGHT_LIGHT = :light
|
|
292
|
+
|
|
293
|
+
SLANT_NORMAL = :normal
|
|
294
|
+
SLANT_ITALIC = :italic
|
|
295
|
+
SLANT_OBLIQUE = :oblique
|
|
296
|
+
|
|
297
|
+
def initialize(
|
|
298
|
+
base:,
|
|
299
|
+
weight: WEIGHT_NORMAL,
|
|
300
|
+
slant: SLANT_NORMAL,
|
|
301
|
+
underline: false,
|
|
302
|
+
strikethrough: false
|
|
303
|
+
)
|
|
304
|
+
@base = base
|
|
305
|
+
@weight = weight
|
|
306
|
+
@slant = slant
|
|
307
|
+
@underline = underline
|
|
308
|
+
@strikethrough = strikethrough
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def bold?
|
|
312
|
+
@weight == WEIGHT_BOLD
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def italic?
|
|
316
|
+
@slant == SLANT_ITALIC
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def underlined?
|
|
320
|
+
@underline
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
def strikethrough?
|
|
324
|
+
@strikethrough
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def type_name
|
|
328
|
+
'RichTextStyle'
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
class TextPipeline
|
|
333
|
+
attr_reader :fonts
|
|
334
|
+
|
|
335
|
+
def initialize
|
|
336
|
+
@fonts = {}
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def register_font(name, font)
|
|
340
|
+
@fonts[name] = font
|
|
341
|
+
self
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def get_font(name)
|
|
345
|
+
@fonts[name]
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def type_name
|
|
349
|
+
'TextPipeline'
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
class TextMeasure
|
|
354
|
+
def self.measure(text, style, max_width: nil)
|
|
355
|
+
char_width = style.font_size * 0.6
|
|
356
|
+
line_height = style.font_size * 1.2
|
|
357
|
+
|
|
358
|
+
full_text = text.is_a?(Text) ? text.full_text : text.to_s
|
|
359
|
+
lines = full_text.split("\n")
|
|
360
|
+
|
|
361
|
+
if max_width
|
|
362
|
+
lines = lines.flat_map { |line| wrap_line(line, char_width, max_width) }
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
width = lines.map { |line| line.length * char_width }.max || 0.0
|
|
366
|
+
height = lines.size * line_height
|
|
367
|
+
|
|
368
|
+
Vec2.new(width, height)
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def self.wrap_line(line, char_width, max_width)
|
|
372
|
+
chars_per_line = (max_width / char_width).floor
|
|
373
|
+
return [line] if line.length <= chars_per_line
|
|
374
|
+
|
|
375
|
+
wrapped = []
|
|
376
|
+
remaining = line
|
|
377
|
+
while remaining.length > chars_per_line
|
|
378
|
+
break_point = remaining.rindex(' ', chars_per_line) || chars_per_line
|
|
379
|
+
wrapped << remaining[0...break_point]
|
|
380
|
+
remaining = remaining[(break_point + 1)..-1] || ''
|
|
381
|
+
end
|
|
382
|
+
wrapped << remaining unless remaining.empty?
|
|
383
|
+
wrapped
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def type_name
|
|
387
|
+
'TextMeasure'
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
class TypewriterEffect
|
|
392
|
+
attr_accessor :text, :visible_chars, :chars_per_second, :timer
|
|
393
|
+
|
|
394
|
+
def initialize(text:, chars_per_second: 30.0)
|
|
395
|
+
@text = text
|
|
396
|
+
@chars_per_second = chars_per_second.to_f
|
|
397
|
+
@visible_chars = 0
|
|
398
|
+
@timer = 0.0
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def update(delta)
|
|
402
|
+
@timer += delta
|
|
403
|
+
chars_to_add = (@timer * @chars_per_second).floor
|
|
404
|
+
@timer -= chars_to_add / @chars_per_second
|
|
405
|
+
@visible_chars = [@visible_chars + chars_to_add, total_chars].min
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
def total_chars
|
|
409
|
+
@text.length
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
def visible_text
|
|
413
|
+
@text[0...@visible_chars]
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
def finished?
|
|
417
|
+
@visible_chars >= total_chars
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
def reset
|
|
421
|
+
@visible_chars = 0
|
|
422
|
+
@timer = 0.0
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
def skip
|
|
426
|
+
@visible_chars = total_chars
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
def type_name
|
|
430
|
+
'TypewriterEffect'
|
|
431
|
+
end
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
class TextBlink
|
|
435
|
+
attr_accessor :visible, :interval, :timer
|
|
436
|
+
|
|
437
|
+
def initialize(interval: 0.5)
|
|
438
|
+
@interval = interval.to_f
|
|
439
|
+
@visible = true
|
|
440
|
+
@timer = 0.0
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
def update(delta)
|
|
444
|
+
@timer += delta
|
|
445
|
+
while @timer >= @interval
|
|
446
|
+
@timer -= @interval
|
|
447
|
+
@visible = !@visible
|
|
448
|
+
end
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
def type_name
|
|
452
|
+
'TextBlink'
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
end
|
data/lib/bevy/timer.rb
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bevy
|
|
4
|
+
class Timer
|
|
5
|
+
attr_reader :duration, :elapsed, :mode
|
|
6
|
+
|
|
7
|
+
module TimerMode
|
|
8
|
+
ONCE = :once
|
|
9
|
+
REPEATING = :repeating
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def initialize(duration, mode: TimerMode::ONCE)
|
|
13
|
+
@duration = duration.to_f
|
|
14
|
+
@elapsed = 0.0
|
|
15
|
+
@mode = mode
|
|
16
|
+
@finished = false
|
|
17
|
+
@just_finished = false
|
|
18
|
+
@times_finished = 0
|
|
19
|
+
@paused = false
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.from_seconds(seconds, mode: TimerMode::ONCE)
|
|
23
|
+
new(seconds, mode: mode)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def tick(delta)
|
|
27
|
+
@just_finished = false
|
|
28
|
+
|
|
29
|
+
return self if @paused
|
|
30
|
+
return self if @mode == TimerMode::ONCE && @finished
|
|
31
|
+
|
|
32
|
+
@elapsed += delta
|
|
33
|
+
|
|
34
|
+
if @elapsed >= @duration
|
|
35
|
+
@times_finished += 1
|
|
36
|
+
@just_finished = true
|
|
37
|
+
|
|
38
|
+
if @mode == TimerMode::REPEATING
|
|
39
|
+
@elapsed -= @duration
|
|
40
|
+
else
|
|
41
|
+
@elapsed = @duration
|
|
42
|
+
@finished = true
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
self
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def finished?
|
|
50
|
+
@finished
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def just_finished?
|
|
54
|
+
@just_finished
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def percent
|
|
58
|
+
return 1.0 if @duration <= 0.0
|
|
59
|
+
|
|
60
|
+
(@elapsed / @duration).clamp(0.0, 1.0)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def percent_left
|
|
64
|
+
1.0 - percent
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def remaining
|
|
68
|
+
(@duration - @elapsed).clamp(0.0, @duration)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def times_finished_this_tick
|
|
72
|
+
@just_finished ? 1 : 0
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def reset
|
|
76
|
+
@elapsed = 0.0
|
|
77
|
+
@finished = false
|
|
78
|
+
@just_finished = false
|
|
79
|
+
self
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def pause
|
|
83
|
+
@paused = true
|
|
84
|
+
self
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def unpause
|
|
88
|
+
@paused = false
|
|
89
|
+
self
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def paused?
|
|
93
|
+
@paused
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def repeating?
|
|
97
|
+
@mode == TimerMode::REPEATING
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def set_duration(duration)
|
|
101
|
+
@duration = duration.to_f
|
|
102
|
+
self
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def set_elapsed(elapsed)
|
|
106
|
+
@elapsed = elapsed.to_f
|
|
107
|
+
self
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
class Stopwatch
|
|
112
|
+
attr_reader :elapsed
|
|
113
|
+
|
|
114
|
+
def initialize
|
|
115
|
+
@elapsed = 0.0
|
|
116
|
+
@paused = false
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def tick(delta)
|
|
120
|
+
@elapsed += delta unless @paused
|
|
121
|
+
self
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def pause
|
|
125
|
+
@paused = true
|
|
126
|
+
self
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def unpause
|
|
130
|
+
@paused = false
|
|
131
|
+
self
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def paused?
|
|
135
|
+
@paused
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def reset
|
|
139
|
+
@elapsed = 0.0
|
|
140
|
+
self
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def elapsed_secs
|
|
144
|
+
@elapsed
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|