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
data/lib/bevy/input.rb ADDED
@@ -0,0 +1,514 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bevy
4
+ module KeyCode
5
+ A = 'A'
6
+ B = 'B'
7
+ C = 'C'
8
+ D = 'D'
9
+ E = 'E'
10
+ F = 'F'
11
+ G = 'G'
12
+ H = 'H'
13
+ I = 'I'
14
+ J = 'J'
15
+ K = 'K'
16
+ L = 'L'
17
+ M = 'M'
18
+ N = 'N'
19
+ O = 'O'
20
+ P = 'P'
21
+ Q = 'Q'
22
+ R = 'R'
23
+ S = 'S'
24
+ T = 'T'
25
+ U = 'U'
26
+ V = 'V'
27
+ W = 'W'
28
+ X = 'X'
29
+ Y = 'Y'
30
+ Z = 'Z'
31
+
32
+ KEY_0 = 'Key0'
33
+ KEY_1 = 'Key1'
34
+ KEY_2 = 'Key2'
35
+ KEY_3 = 'Key3'
36
+ KEY_4 = 'Key4'
37
+ KEY_5 = 'Key5'
38
+ KEY_6 = 'Key6'
39
+ KEY_7 = 'Key7'
40
+ KEY_8 = 'Key8'
41
+ KEY_9 = 'Key9'
42
+
43
+ ESCAPE = 'Escape'
44
+ ENTER = 'Enter'
45
+ SPACE = 'Space'
46
+ BACKSPACE = 'Backspace'
47
+ TAB = 'Tab'
48
+
49
+ LEFT = 'ArrowLeft'
50
+ RIGHT = 'ArrowRight'
51
+ UP = 'ArrowUp'
52
+ DOWN = 'ArrowDown'
53
+
54
+ LEFT_SHIFT = 'ShiftLeft'
55
+ RIGHT_SHIFT = 'ShiftRight'
56
+ LEFT_CONTROL = 'ControlLeft'
57
+ RIGHT_CONTROL = 'ControlRight'
58
+ LEFT_ALT = 'AltLeft'
59
+ RIGHT_ALT = 'AltRight'
60
+
61
+ F1 = 'F1'
62
+ F2 = 'F2'
63
+ F3 = 'F3'
64
+ F4 = 'F4'
65
+ F5 = 'F5'
66
+ F6 = 'F6'
67
+ F7 = 'F7'
68
+ F8 = 'F8'
69
+ F9 = 'F9'
70
+ F10 = 'F10'
71
+ F11 = 'F11'
72
+ F12 = 'F12'
73
+ end
74
+
75
+ module MouseButton
76
+ LEFT = 'Left'
77
+ RIGHT = 'Right'
78
+ MIDDLE = 'Middle'
79
+ end
80
+
81
+ class KeyboardInput
82
+ def initialize
83
+ @pressed = {}
84
+ @just_pressed = {}
85
+ @just_released = {}
86
+ @last_frame_pressed = {}
87
+ end
88
+
89
+ def press(key)
90
+ @just_pressed[key] = true unless @pressed[key]
91
+ @pressed[key] = true
92
+ end
93
+
94
+ def release(key)
95
+ @just_released[key] = true if @pressed[key]
96
+ @pressed.delete(key)
97
+ end
98
+
99
+ def pressed?(key)
100
+ @pressed[key] == true
101
+ end
102
+
103
+ def just_pressed?(key)
104
+ @just_pressed[key] == true
105
+ end
106
+
107
+ def just_released?(key)
108
+ @just_released[key] == true
109
+ end
110
+
111
+ def was_pressed_last_frame?(key)
112
+ @last_frame_pressed[key] == true
113
+ end
114
+
115
+ def set_just_pressed(key)
116
+ @just_pressed[key] = true
117
+ end
118
+
119
+ def end_frame
120
+ @last_frame_pressed = @pressed.dup
121
+ end
122
+
123
+ def clear_just_pressed
124
+ @just_pressed.clear
125
+ @just_released.clear
126
+ end
127
+
128
+ def pressed_keys
129
+ @pressed.keys
130
+ end
131
+
132
+ def any_pressed?
133
+ !@pressed.empty?
134
+ end
135
+
136
+ def reset
137
+ @last_frame_pressed = @pressed.dup
138
+ @pressed.clear
139
+ @just_pressed.clear
140
+ @just_released.clear
141
+ end
142
+ end
143
+
144
+ class MouseInput
145
+ attr_reader :position, :delta, :scroll_delta
146
+
147
+ def initialize
148
+ @pressed = {}
149
+ @just_pressed = {}
150
+ @just_released = {}
151
+ @position = Vec2.zero
152
+ @delta = Vec2.zero
153
+ @scroll_delta = Vec2.zero
154
+ end
155
+
156
+ def press(button)
157
+ @just_pressed[button] = true unless @pressed[button]
158
+ @pressed[button] = true
159
+ end
160
+
161
+ def release(button)
162
+ @just_released[button] = true if @pressed[button]
163
+ @pressed.delete(button)
164
+ end
165
+
166
+ def pressed?(button)
167
+ @pressed[button] == true
168
+ end
169
+
170
+ def just_pressed?(button)
171
+ @just_pressed[button] == true
172
+ end
173
+
174
+ def just_released?(button)
175
+ @just_released[button] == true
176
+ end
177
+
178
+ def set_position(x, y)
179
+ old_x = @position.x
180
+ old_y = @position.y
181
+ @position = Vec2.new(x, y)
182
+ @delta = Vec2.new(x - old_x, y - old_y)
183
+ end
184
+
185
+ def set_scroll(x, y)
186
+ @scroll_delta = Vec2.new(x, y)
187
+ end
188
+
189
+ def clear_just_pressed
190
+ @just_pressed.clear
191
+ @just_released.clear
192
+ @delta = Vec2.zero
193
+ @scroll_delta = Vec2.zero
194
+ end
195
+
196
+ def reset
197
+ @pressed.clear
198
+ @just_pressed.clear
199
+ @just_released.clear
200
+ @position = Vec2.zero
201
+ @delta = Vec2.zero
202
+ @scroll_delta = Vec2.zero
203
+ end
204
+ end
205
+
206
+ module GamepadButton
207
+ SOUTH = 'South'
208
+ EAST = 'East'
209
+ NORTH = 'North'
210
+ WEST = 'West'
211
+ LEFT_TRIGGER = 'LeftTrigger'
212
+ LEFT_TRIGGER2 = 'LeftTrigger2'
213
+ RIGHT_TRIGGER = 'RightTrigger'
214
+ RIGHT_TRIGGER2 = 'RightTrigger2'
215
+ SELECT = 'Select'
216
+ START = 'Start'
217
+ MODE = 'Mode'
218
+ LEFT_THUMB = 'LeftThumb'
219
+ RIGHT_THUMB = 'RightThumb'
220
+ DPAD_UP = 'DPadUp'
221
+ DPAD_DOWN = 'DPadDown'
222
+ DPAD_LEFT = 'DPadLeft'
223
+ DPAD_RIGHT = 'DPadRight'
224
+ end
225
+
226
+ module GamepadAxis
227
+ LEFT_STICK_X = 'LeftStickX'
228
+ LEFT_STICK_Y = 'LeftStickY'
229
+ RIGHT_STICK_X = 'RightStickX'
230
+ RIGHT_STICK_Y = 'RightStickY'
231
+ LEFT_TRIGGER = 'LeftZ'
232
+ RIGHT_TRIGGER = 'RightZ'
233
+ end
234
+
235
+ class DeadZone
236
+ attr_reader :inner, :outer
237
+
238
+ def initialize(inner: 0.1, outer: 0.95)
239
+ @inner = inner.clamp(0.0, 1.0)
240
+ @outer = outer.clamp(0.0, 1.0)
241
+ end
242
+
243
+ def apply(value)
244
+ abs_value = value.abs
245
+ return 0.0 if abs_value < @inner
246
+ return value / value.abs if abs_value > @outer
247
+
248
+ normalized = (abs_value - @inner) / (@outer - @inner)
249
+ normalized * (value / value.abs)
250
+ end
251
+
252
+ def apply_vec2(vec)
253
+ len = Math.sqrt(vec.x * vec.x + vec.y * vec.y)
254
+ return Vec2.zero if len < @inner
255
+ return vec.normalize if len > @outer
256
+
257
+ normalized_len = (len - @inner) / (@outer - @inner)
258
+ normalized = vec.normalize
259
+ Vec2.new(normalized.x * normalized_len, normalized.y * normalized_len)
260
+ end
261
+ end
262
+
263
+ class RumbleRequest
264
+ attr_reader :strong_magnitude, :weak_magnitude, :duration
265
+
266
+ def initialize(strong: 0.0, weak: 0.0, duration: 0.0)
267
+ @strong_magnitude = strong.clamp(0.0, 1.0)
268
+ @weak_magnitude = weak.clamp(0.0, 1.0)
269
+ @duration = [duration, 0.0].max
270
+ end
271
+
272
+ def self.strong(magnitude, duration)
273
+ new(strong: magnitude, weak: 0.0, duration: duration)
274
+ end
275
+
276
+ def self.weak(magnitude, duration)
277
+ new(strong: 0.0, weak: magnitude, duration: duration)
278
+ end
279
+
280
+ def self.both(magnitude, duration)
281
+ new(strong: magnitude, weak: magnitude, duration: duration)
282
+ end
283
+ end
284
+
285
+ class GamepadInput
286
+ attr_reader :id, :name
287
+ attr_accessor :stick_dead_zone
288
+
289
+ def initialize(id = 0, name: nil)
290
+ @id = id
291
+ @name = name || "Gamepad #{id}"
292
+ @pressed = {}
293
+ @just_pressed = {}
294
+ @just_released = {}
295
+ @button_values = {}
296
+ @axes = {}
297
+ @axis_dead_zones = {}
298
+ @stick_dead_zone = DeadZone.new
299
+ @pending_rumble = nil
300
+ end
301
+
302
+ def press(button)
303
+ @just_pressed[button] = true unless @pressed[button]
304
+ @pressed[button] = true
305
+ @button_values[button] = 1.0
306
+ end
307
+
308
+ def release(button)
309
+ @just_released[button] = true if @pressed[button]
310
+ @pressed.delete(button)
311
+ @button_values[button] = 0.0
312
+ end
313
+
314
+ def set_button_value(button, value)
315
+ was_pressed = @pressed[button]
316
+ @button_values[button] = value
317
+ @pressed[button] = value > 0.5
318
+ if !was_pressed && @pressed[button]
319
+ @just_pressed[button] = true
320
+ elsif was_pressed && !@pressed[button]
321
+ @just_released[button] = true
322
+ end
323
+ end
324
+
325
+ def button_value(button)
326
+ @button_values[button] || 0.0
327
+ end
328
+
329
+ def known_buttons
330
+ @button_values.keys
331
+ end
332
+
333
+ def pressed?(button)
334
+ @pressed[button] == true
335
+ end
336
+
337
+ def just_pressed?(button)
338
+ @just_pressed[button] == true
339
+ end
340
+
341
+ def just_released?(button)
342
+ @just_released[button] == true
343
+ end
344
+
345
+ def set_axis_dead_zone(axis, dead_zone)
346
+ @axis_dead_zones[axis] = dead_zone
347
+ end
348
+
349
+ def set_axis(axis, value)
350
+ @axes[axis] = value.clamp(-1.0, 1.0)
351
+ end
352
+
353
+ def axis_raw(axis)
354
+ @axes[axis] || 0.0
355
+ end
356
+
357
+ def known_axes
358
+ @axes.keys
359
+ end
360
+
361
+ def axis(axis)
362
+ raw = axis_raw(axis)
363
+ dead_zone = @axis_dead_zones[axis] || DeadZone.new
364
+ dead_zone.apply(raw)
365
+ end
366
+
367
+ def left_stick_raw
368
+ Vec2.new(
369
+ axis_raw(GamepadAxis::LEFT_STICK_X),
370
+ axis_raw(GamepadAxis::LEFT_STICK_Y)
371
+ )
372
+ end
373
+
374
+ def left_stick
375
+ @stick_dead_zone.apply_vec2(left_stick_raw)
376
+ end
377
+
378
+ def right_stick_raw
379
+ Vec2.new(
380
+ axis_raw(GamepadAxis::RIGHT_STICK_X),
381
+ axis_raw(GamepadAxis::RIGHT_STICK_Y)
382
+ )
383
+ end
384
+
385
+ def right_stick
386
+ @stick_dead_zone.apply_vec2(right_stick_raw)
387
+ end
388
+
389
+ def left_trigger
390
+ [axis(GamepadAxis::LEFT_TRIGGER), 0.0].max
391
+ end
392
+
393
+ def right_trigger
394
+ [axis(GamepadAxis::RIGHT_TRIGGER), 0.0].max
395
+ end
396
+
397
+ def rumble(request)
398
+ @pending_rumble = request
399
+ end
400
+
401
+ def rumble_strong(magnitude, duration)
402
+ @pending_rumble = RumbleRequest.strong(magnitude, duration)
403
+ end
404
+
405
+ def rumble_weak(magnitude, duration)
406
+ @pending_rumble = RumbleRequest.weak(magnitude, duration)
407
+ end
408
+
409
+ def rumble_both(magnitude, duration)
410
+ @pending_rumble = RumbleRequest.both(magnitude, duration)
411
+ end
412
+
413
+ def stop_rumble
414
+ @pending_rumble = RumbleRequest.new
415
+ end
416
+
417
+ def pending_rumble
418
+ @pending_rumble
419
+ end
420
+
421
+ def clear_pending_rumble
422
+ @pending_rumble = nil
423
+ end
424
+
425
+ def clear_just_pressed
426
+ @just_pressed.clear
427
+ @just_released.clear
428
+ end
429
+
430
+ def reset
431
+ @pressed.clear
432
+ @just_pressed.clear
433
+ @just_released.clear
434
+ @button_values.clear
435
+ @axes.clear
436
+ @pending_rumble = nil
437
+ end
438
+ end
439
+
440
+ class Gamepads
441
+ attr_accessor :default_dead_zone
442
+
443
+ def initialize
444
+ @gamepads = {}
445
+ @default_dead_zone = DeadZone.new
446
+ end
447
+
448
+ def connect(id, name: nil)
449
+ gamepad = GamepadInput.new(id, name: name)
450
+ gamepad.stick_dead_zone = @default_dead_zone
451
+ @gamepads[id] = gamepad
452
+ end
453
+
454
+ def disconnect(id)
455
+ @gamepads.delete(id)
456
+ end
457
+
458
+ def connected?(id)
459
+ @gamepads.key?(id)
460
+ end
461
+
462
+ def get(id)
463
+ @gamepads[id]
464
+ end
465
+
466
+ def [](id)
467
+ @gamepads[id]
468
+ end
469
+
470
+ def connected_ids
471
+ @gamepads.keys
472
+ end
473
+
474
+ def count
475
+ @gamepads.size
476
+ end
477
+
478
+ def any?
479
+ !@gamepads.empty?
480
+ end
481
+
482
+ def first
483
+ @gamepads.values.first
484
+ end
485
+
486
+ def each(&block)
487
+ @gamepads.values.each(&block)
488
+ end
489
+
490
+ def any_pressed?(button)
491
+ @gamepads.values.any? { |gp| gp.pressed?(button) }
492
+ end
493
+
494
+ def any_just_pressed?(button)
495
+ @gamepads.values.any? { |gp| gp.just_pressed?(button) }
496
+ end
497
+
498
+ def any_just_released?(button)
499
+ @gamepads.values.any? { |gp| gp.just_released?(button) }
500
+ end
501
+
502
+ def clear_just_pressed
503
+ @gamepads.each_value(&:clear_just_pressed)
504
+ end
505
+
506
+ def clear_pending_rumbles
507
+ @gamepads.each_value(&:clear_pending_rumble)
508
+ end
509
+
510
+ def reset_all
511
+ @gamepads.each_value(&:reset)
512
+ end
513
+ end
514
+ end