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.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/Cargo.lock +4279 -0
  3. data/Cargo.toml +36 -0
  4. data/README.md +226 -0
  5. data/crates/bevy/Cargo.toml +52 -0
  6. data/crates/bevy/src/app.rs +43 -0
  7. data/crates/bevy/src/component.rs +111 -0
  8. data/crates/bevy/src/entity.rs +30 -0
  9. data/crates/bevy/src/error.rs +32 -0
  10. data/crates/bevy/src/event.rs +190 -0
  11. data/crates/bevy/src/input_bridge.rs +300 -0
  12. data/crates/bevy/src/lib.rs +42 -0
  13. data/crates/bevy/src/mesh_renderer.rs +328 -0
  14. data/crates/bevy/src/query.rs +53 -0
  15. data/crates/bevy/src/render_app.rs +689 -0
  16. data/crates/bevy/src/resource.rs +28 -0
  17. data/crates/bevy/src/schedule.rs +186 -0
  18. data/crates/bevy/src/sprite_renderer.rs +355 -0
  19. data/crates/bevy/src/system.rs +44 -0
  20. data/crates/bevy/src/text_renderer.rs +258 -0
  21. data/crates/bevy/src/types/color.rs +114 -0
  22. data/crates/bevy/src/types/dynamic.rs +131 -0
  23. data/crates/bevy/src/types/math.rs +260 -0
  24. data/crates/bevy/src/types/mod.rs +9 -0
  25. data/crates/bevy/src/types/transform.rs +166 -0
  26. data/crates/bevy/src/world.rs +163 -0
  27. data/crates/bevy_ruby_render/Cargo.toml +22 -0
  28. data/crates/bevy_ruby_render/src/asset.rs +360 -0
  29. data/crates/bevy_ruby_render/src/audio.rs +511 -0
  30. data/crates/bevy_ruby_render/src/camera.rs +365 -0
  31. data/crates/bevy_ruby_render/src/gamepad.rs +398 -0
  32. data/crates/bevy_ruby_render/src/lib.rs +26 -0
  33. data/crates/bevy_ruby_render/src/material.rs +310 -0
  34. data/crates/bevy_ruby_render/src/mesh.rs +491 -0
  35. data/crates/bevy_ruby_render/src/sprite.rs +289 -0
  36. data/ext/bevy/Cargo.toml +20 -0
  37. data/ext/bevy/extconf.rb +6 -0
  38. data/ext/bevy/src/conversions.rs +137 -0
  39. data/ext/bevy/src/lib.rs +29 -0
  40. data/ext/bevy/src/ruby_app.rs +65 -0
  41. data/ext/bevy/src/ruby_color.rs +149 -0
  42. data/ext/bevy/src/ruby_component.rs +189 -0
  43. data/ext/bevy/src/ruby_entity.rs +33 -0
  44. data/ext/bevy/src/ruby_math.rs +384 -0
  45. data/ext/bevy/src/ruby_query.rs +64 -0
  46. data/ext/bevy/src/ruby_render_app.rs +779 -0
  47. data/ext/bevy/src/ruby_system.rs +122 -0
  48. data/ext/bevy/src/ruby_world.rs +107 -0
  49. data/lib/bevy/animation.rb +597 -0
  50. data/lib/bevy/app.rb +675 -0
  51. data/lib/bevy/asset.rb +613 -0
  52. data/lib/bevy/audio.rb +545 -0
  53. data/lib/bevy/audio_effects.rb +224 -0
  54. data/lib/bevy/camera.rb +412 -0
  55. data/lib/bevy/component.rb +91 -0
  56. data/lib/bevy/diagnostics.rb +227 -0
  57. data/lib/bevy/ecs_advanced.rb +296 -0
  58. data/lib/bevy/event.rb +199 -0
  59. data/lib/bevy/gizmos.rb +158 -0
  60. data/lib/bevy/gltf.rb +227 -0
  61. data/lib/bevy/hierarchy.rb +444 -0
  62. data/lib/bevy/input.rb +514 -0
  63. data/lib/bevy/lighting.rb +369 -0
  64. data/lib/bevy/material.rb +248 -0
  65. data/lib/bevy/mesh.rb +257 -0
  66. data/lib/bevy/navigation.rb +344 -0
  67. data/lib/bevy/networking.rb +335 -0
  68. data/lib/bevy/particle.rb +337 -0
  69. data/lib/bevy/physics.rb +396 -0
  70. data/lib/bevy/plugins/default_plugins.rb +34 -0
  71. data/lib/bevy/plugins/input_plugin.rb +49 -0
  72. data/lib/bevy/reflect.rb +361 -0
  73. data/lib/bevy/render_graph.rb +210 -0
  74. data/lib/bevy/resource.rb +185 -0
  75. data/lib/bevy/scene.rb +254 -0
  76. data/lib/bevy/shader.rb +319 -0
  77. data/lib/bevy/shape.rb +195 -0
  78. data/lib/bevy/skeletal.rb +248 -0
  79. data/lib/bevy/sprite.rb +152 -0
  80. data/lib/bevy/sprite_sheet.rb +444 -0
  81. data/lib/bevy/state.rb +277 -0
  82. data/lib/bevy/system.rb +206 -0
  83. data/lib/bevy/text.rb +99 -0
  84. data/lib/bevy/text_advanced.rb +455 -0
  85. data/lib/bevy/timer.rb +147 -0
  86. data/lib/bevy/transform.rb +158 -0
  87. data/lib/bevy/ui.rb +454 -0
  88. data/lib/bevy/ui_advanced.rb +568 -0
  89. data/lib/bevy/version.rb +5 -0
  90. data/lib/bevy/visibility.rb +250 -0
  91. data/lib/bevy/window.rb +302 -0
  92. data/lib/bevy.rb +390 -0
  93. 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