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,568 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bevy
4
+ class ScrollView
5
+ attr_accessor :offset, :content_size, :viewport_size
6
+ attr_accessor :scroll_x, :scroll_y, :overscroll_behavior
7
+
8
+ OVERSCROLL_NONE = :none
9
+ OVERSCROLL_CONTAIN = :contain
10
+ OVERSCROLL_AUTO = :auto
11
+
12
+ def initialize(
13
+ scroll_x: true,
14
+ scroll_y: true,
15
+ overscroll_behavior: OVERSCROLL_CONTAIN
16
+ )
17
+ @offset = Vec2.zero
18
+ @content_size = Vec2.zero
19
+ @viewport_size = Vec2.zero
20
+ @scroll_x = scroll_x
21
+ @scroll_y = scroll_y
22
+ @overscroll_behavior = overscroll_behavior
23
+ end
24
+
25
+ def scroll_by(delta)
26
+ new_offset_x = @scroll_x ? @offset.x + delta.x : @offset.x
27
+ new_offset_y = @scroll_y ? @offset.y + delta.y : @offset.y
28
+
29
+ if @overscroll_behavior == OVERSCROLL_CONTAIN
30
+ max_x = [@content_size.x - @viewport_size.x, 0.0].max
31
+ max_y = [@content_size.y - @viewport_size.y, 0.0].max
32
+ new_offset_x = [[new_offset_x, 0.0].max, max_x].min
33
+ new_offset_y = [[new_offset_y, 0.0].max, max_y].min
34
+ end
35
+
36
+ @offset = Vec2.new(new_offset_x, new_offset_y)
37
+ end
38
+
39
+ def scroll_to(position)
40
+ @offset = position
41
+ end
42
+
43
+ def scroll_to_top
44
+ @offset = Vec2.new(@offset.x, 0.0)
45
+ end
46
+
47
+ def scroll_to_bottom
48
+ max_y = [@content_size.y - @viewport_size.y, 0.0].max
49
+ @offset = Vec2.new(@offset.x, max_y)
50
+ end
51
+
52
+ def scroll_percentage
53
+ return Vec2.zero if @content_size.x <= @viewport_size.x && @content_size.y <= @viewport_size.y
54
+
55
+ max_x = [@content_size.x - @viewport_size.x, 1.0].max
56
+ max_y = [@content_size.y - @viewport_size.y, 1.0].max
57
+ Vec2.new(@offset.x / max_x, @offset.y / max_y)
58
+ end
59
+
60
+ def type_name
61
+ 'ScrollView'
62
+ end
63
+ end
64
+
65
+ class TextInput
66
+ attr_accessor :value, :placeholder, :cursor_position, :selection_start, :selection_end
67
+ attr_accessor :max_length, :multiline, :password, :readonly, :focused
68
+
69
+ def initialize(
70
+ value: '',
71
+ placeholder: '',
72
+ max_length: nil,
73
+ multiline: false,
74
+ password: false,
75
+ readonly: false
76
+ )
77
+ @value = value
78
+ @placeholder = placeholder
79
+ @cursor_position = value.length
80
+ @selection_start = nil
81
+ @selection_end = nil
82
+ @max_length = max_length
83
+ @multiline = multiline
84
+ @password = password
85
+ @readonly = readonly
86
+ @focused = false
87
+ end
88
+
89
+ def insert(text)
90
+ return if @readonly
91
+ return if @max_length && @value.length + text.length > @max_length
92
+
93
+ delete_selection if has_selection?
94
+
95
+ @value = @value[0...@cursor_position] + text + @value[@cursor_position..-1]
96
+ @cursor_position += text.length
97
+ end
98
+
99
+ def delete_backward
100
+ return if @readonly
101
+ return if @cursor_position == 0 && !has_selection?
102
+
103
+ if has_selection?
104
+ delete_selection
105
+ else
106
+ @value = @value[0...(@cursor_position - 1)] + @value[@cursor_position..-1]
107
+ @cursor_position -= 1
108
+ end
109
+ end
110
+
111
+ def delete_forward
112
+ return if @readonly
113
+ return if @cursor_position >= @value.length && !has_selection?
114
+
115
+ if has_selection?
116
+ delete_selection
117
+ else
118
+ @value = @value[0...@cursor_position] + @value[(@cursor_position + 1)..-1]
119
+ end
120
+ end
121
+
122
+ def move_cursor(direction)
123
+ case direction
124
+ when :left
125
+ @cursor_position = [@cursor_position - 1, 0].max
126
+ when :right
127
+ @cursor_position = [@cursor_position + 1, @value.length].min
128
+ when :home
129
+ @cursor_position = 0
130
+ when :end
131
+ @cursor_position = @value.length
132
+ end
133
+ clear_selection
134
+ end
135
+
136
+ def select_all
137
+ @selection_start = 0
138
+ @selection_end = @value.length
139
+ @cursor_position = @value.length
140
+ end
141
+
142
+ def clear_selection
143
+ @selection_start = nil
144
+ @selection_end = nil
145
+ end
146
+
147
+ def has_selection?
148
+ @selection_start && @selection_end && @selection_start != @selection_end
149
+ end
150
+
151
+ def selected_text
152
+ return '' unless has_selection?
153
+
154
+ start_pos = [@selection_start, @selection_end].min
155
+ end_pos = [@selection_start, @selection_end].max
156
+ @value[start_pos...end_pos]
157
+ end
158
+
159
+ def display_value
160
+ @password ? '*' * @value.length : @value
161
+ end
162
+
163
+ def type_name
164
+ 'TextInput'
165
+ end
166
+
167
+ private
168
+
169
+ def delete_selection
170
+ return unless has_selection?
171
+
172
+ start_pos = [@selection_start, @selection_end].min
173
+ end_pos = [@selection_start, @selection_end].max
174
+ @value = @value[0...start_pos] + @value[end_pos..-1]
175
+ @cursor_position = start_pos
176
+ clear_selection
177
+ end
178
+ end
179
+
180
+ class FocusState
181
+ attr_reader :focused_entity, :focus_order
182
+
183
+ def initialize
184
+ @focused_entity = nil
185
+ @focus_order = []
186
+ end
187
+
188
+ def focus(entity)
189
+ @focused_entity = entity
190
+ end
191
+
192
+ def blur
193
+ @focused_entity = nil
194
+ end
195
+
196
+ def focused?(entity)
197
+ @focused_entity == entity
198
+ end
199
+
200
+ def register(entity, order: nil)
201
+ if order
202
+ @focus_order.insert(order, entity)
203
+ else
204
+ @focus_order << entity
205
+ end
206
+ end
207
+
208
+ def unregister(entity)
209
+ @focus_order.delete(entity)
210
+ blur if @focused_entity == entity
211
+ end
212
+
213
+ def focus_next
214
+ return if @focus_order.empty?
215
+
216
+ current_index = @focused_entity ? @focus_order.index(@focused_entity) : -1
217
+ next_index = (current_index + 1) % @focus_order.length
218
+ @focused_entity = @focus_order[next_index]
219
+ end
220
+
221
+ def focus_previous
222
+ return if @focus_order.empty?
223
+
224
+ current_index = @focused_entity ? @focus_order.index(@focused_entity) : @focus_order.length
225
+ prev_index = (current_index - 1) % @focus_order.length
226
+ @focused_entity = @focus_order[prev_index]
227
+ end
228
+
229
+ def type_name
230
+ 'FocusState'
231
+ end
232
+ end
233
+
234
+ class Slider
235
+ attr_accessor :value, :min, :max, :step, :orientation, :disabled
236
+
237
+ HORIZONTAL = :horizontal
238
+ VERTICAL = :vertical
239
+
240
+ def initialize(
241
+ value: 0.0,
242
+ min: 0.0,
243
+ max: 1.0,
244
+ step: nil,
245
+ orientation: HORIZONTAL,
246
+ disabled: false
247
+ )
248
+ @min = min.to_f
249
+ @max = max.to_f
250
+ @step = step
251
+ @orientation = orientation
252
+ @disabled = disabled
253
+ self.value = value
254
+ end
255
+
256
+ def value=(val)
257
+ clamped = [[val.to_f, @min].max, @max].min
258
+ @value = @step ? (clamped / @step).round * @step : clamped
259
+ end
260
+
261
+ def normalized_value
262
+ return 0.0 if @max == @min
263
+
264
+ (@value - @min) / (@max - @min)
265
+ end
266
+
267
+ def set_from_normalized(normalized)
268
+ self.value = @min + normalized * (@max - @min)
269
+ end
270
+
271
+ def increment
272
+ return if @disabled
273
+
274
+ self.value = @value + (@step || (@max - @min) / 10.0)
275
+ end
276
+
277
+ def decrement
278
+ return if @disabled
279
+
280
+ self.value = @value - (@step || (@max - @min) / 10.0)
281
+ end
282
+
283
+ def type_name
284
+ 'Slider'
285
+ end
286
+ end
287
+
288
+ class Checkbox
289
+ attr_accessor :checked, :disabled, :label
290
+
291
+ def initialize(checked: false, disabled: false, label: nil)
292
+ @checked = checked
293
+ @disabled = disabled
294
+ @label = label
295
+ end
296
+
297
+ def toggle
298
+ return if @disabled
299
+
300
+ @checked = !@checked
301
+ end
302
+
303
+ def type_name
304
+ 'Checkbox'
305
+ end
306
+ end
307
+
308
+ class RadioGroup
309
+ attr_reader :options, :selected_index, :name
310
+
311
+ def initialize(name:, options: [])
312
+ @name = name
313
+ @options = options
314
+ @selected_index = nil
315
+ end
316
+
317
+ def add_option(option)
318
+ @options << option
319
+ self
320
+ end
321
+
322
+ def select(index)
323
+ return if index < 0 || index >= @options.length
324
+
325
+ @selected_index = index
326
+ end
327
+
328
+ def select_value(value)
329
+ index = @options.index(value)
330
+ select(index) if index
331
+ end
332
+
333
+ def selected_value
334
+ @selected_index ? @options[@selected_index] : nil
335
+ end
336
+
337
+ def selected?(index)
338
+ @selected_index == index
339
+ end
340
+
341
+ def type_name
342
+ 'RadioGroup'
343
+ end
344
+ end
345
+
346
+ class Dropdown
347
+ attr_accessor :options, :selected_index, :open, :placeholder, :disabled
348
+
349
+ def initialize(
350
+ options: [],
351
+ selected_index: nil,
352
+ placeholder: 'Select...',
353
+ disabled: false
354
+ )
355
+ @options = options
356
+ @selected_index = selected_index
357
+ @open = false
358
+ @placeholder = placeholder
359
+ @disabled = disabled
360
+ end
361
+
362
+ def toggle
363
+ return if @disabled
364
+
365
+ @open = !@open
366
+ end
367
+
368
+ def close
369
+ @open = false
370
+ end
371
+
372
+ def select(index)
373
+ return if index < 0 || index >= @options.length
374
+
375
+ @selected_index = index
376
+ @open = false
377
+ end
378
+
379
+ def selected_value
380
+ @selected_index ? @options[@selected_index] : nil
381
+ end
382
+
383
+ def display_text
384
+ selected_value || @placeholder
385
+ end
386
+
387
+ def type_name
388
+ 'Dropdown'
389
+ end
390
+ end
391
+
392
+ class TabContainer
393
+ attr_reader :tabs, :active_index
394
+
395
+ def initialize
396
+ @tabs = []
397
+ @active_index = 0
398
+ end
399
+
400
+ def add_tab(title, content = nil)
401
+ @tabs << { title: title, content: content }
402
+ self
403
+ end
404
+
405
+ def remove_tab(index)
406
+ return if index < 0 || index >= @tabs.length
407
+
408
+ @tabs.delete_at(index)
409
+ @active_index = [@active_index, @tabs.length - 1].min if @active_index >= @tabs.length
410
+ end
411
+
412
+ def select_tab(index)
413
+ return if index < 0 || index >= @tabs.length
414
+
415
+ @active_index = index
416
+ end
417
+
418
+ def active_tab
419
+ @tabs[@active_index]
420
+ end
421
+
422
+ def tab_count
423
+ @tabs.length
424
+ end
425
+
426
+ def type_name
427
+ 'TabContainer'
428
+ end
429
+ end
430
+
431
+ class ProgressBar
432
+ attr_accessor :value, :min, :max, :show_label
433
+
434
+ def initialize(value: 0.0, min: 0.0, max: 1.0, show_label: false)
435
+ @min = min.to_f
436
+ @max = max.to_f
437
+ @value = [[value.to_f, @min].max, @max].min
438
+ @show_label = show_label
439
+ end
440
+
441
+ def percentage
442
+ return 0.0 if @max == @min
443
+
444
+ ((@value - @min) / (@max - @min)) * 100.0
445
+ end
446
+
447
+ def normalized
448
+ return 0.0 if @max == @min
449
+
450
+ (@value - @min) / (@max - @min)
451
+ end
452
+
453
+ def complete?
454
+ @value >= @max
455
+ end
456
+
457
+ def type_name
458
+ 'ProgressBar'
459
+ end
460
+ end
461
+
462
+ class Tooltip
463
+ attr_accessor :text, :position, :visible, :delay
464
+
465
+ def initialize(text:, delay: 0.5)
466
+ @text = text
467
+ @position = Vec2.zero
468
+ @visible = false
469
+ @delay = delay.to_f
470
+ @hover_timer = 0.0
471
+ end
472
+
473
+ def update(delta, hovering)
474
+ if hovering
475
+ @hover_timer += delta
476
+ @visible = @hover_timer >= @delay
477
+ else
478
+ @hover_timer = 0.0
479
+ @visible = false
480
+ end
481
+ end
482
+
483
+ def show_at(position)
484
+ @position = position
485
+ @visible = true
486
+ end
487
+
488
+ def hide
489
+ @visible = false
490
+ @hover_timer = 0.0
491
+ end
492
+
493
+ def type_name
494
+ 'Tooltip'
495
+ end
496
+ end
497
+
498
+ class Modal
499
+ attr_accessor :visible, :title, :content, :closable
500
+
501
+ def initialize(title: nil, content: nil, closable: true)
502
+ @visible = false
503
+ @title = title
504
+ @content = content
505
+ @closable = closable
506
+ end
507
+
508
+ def open
509
+ @visible = true
510
+ end
511
+
512
+ def close
513
+ @visible = false if @closable
514
+ end
515
+
516
+ def toggle
517
+ @visible = !@visible
518
+ end
519
+
520
+ def type_name
521
+ 'Modal'
522
+ end
523
+ end
524
+
525
+ class ContextMenu
526
+ attr_reader :items, :position
527
+ attr_accessor :visible
528
+
529
+ def initialize
530
+ @items = []
531
+ @position = Vec2.zero
532
+ @visible = false
533
+ end
534
+
535
+ def add_item(label, action = nil)
536
+ @items << { label: label, action: action, enabled: true }
537
+ self
538
+ end
539
+
540
+ def add_separator
541
+ @items << { separator: true }
542
+ self
543
+ end
544
+
545
+ def show_at(position)
546
+ @position = position
547
+ @visible = true
548
+ end
549
+
550
+ def hide
551
+ @visible = false
552
+ end
553
+
554
+ def select(index)
555
+ return if index < 0 || index >= @items.length
556
+
557
+ item = @items[index]
558
+ return if item[:separator] || !item[:enabled]
559
+
560
+ item[:action]&.call
561
+ hide
562
+ end
563
+
564
+ def type_name
565
+ 'ContextMenu'
566
+ end
567
+ end
568
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bevy
4
+ VERSION = '1.0.0'
5
+ end