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
data/lib/bevy/shader.rb
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bevy
|
|
4
|
+
class ShaderSource
|
|
5
|
+
attr_reader :vertex, :fragment, :compute
|
|
6
|
+
|
|
7
|
+
def initialize(vertex: nil, fragment: nil, compute: nil)
|
|
8
|
+
@vertex = vertex
|
|
9
|
+
@fragment = fragment
|
|
10
|
+
@compute = compute
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def has_vertex?
|
|
14
|
+
!@vertex.nil?
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def has_fragment?
|
|
18
|
+
!@fragment.nil?
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def has_compute?
|
|
22
|
+
!@compute.nil?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def type_name
|
|
26
|
+
'ShaderSource'
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class Shader
|
|
31
|
+
attr_reader :name, :source, :path
|
|
32
|
+
|
|
33
|
+
def initialize(name:, source: nil, path: nil)
|
|
34
|
+
@name = name
|
|
35
|
+
@source = source
|
|
36
|
+
@path = path
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.from_wgsl(name, wgsl_source)
|
|
40
|
+
new(name: name, source: ShaderSource.new(fragment: wgsl_source, vertex: wgsl_source))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.from_file(name, path)
|
|
44
|
+
new(name: name, path: path)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def loaded?
|
|
48
|
+
@source || @path
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def type_name
|
|
52
|
+
'Shader'
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class ShaderDefVal
|
|
57
|
+
attr_reader :key, :value
|
|
58
|
+
|
|
59
|
+
def initialize(key, value)
|
|
60
|
+
@key = key.to_s
|
|
61
|
+
@value = value
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.bool(key, value)
|
|
65
|
+
new(key, value ? 1 : 0)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def self.int(key, value)
|
|
69
|
+
new(key, value.to_i)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self.uint(key, value)
|
|
73
|
+
new(key, value.to_i.abs)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def type_name
|
|
77
|
+
'ShaderDefVal'
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
class ShaderDefs
|
|
82
|
+
def initialize
|
|
83
|
+
@defs = {}
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def set(key, value)
|
|
87
|
+
@defs[key.to_s] = value
|
|
88
|
+
self
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def get(key)
|
|
92
|
+
@defs[key.to_s]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def remove(key)
|
|
96
|
+
@defs.delete(key.to_s)
|
|
97
|
+
self
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def to_h
|
|
101
|
+
@defs.dup
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def type_name
|
|
105
|
+
'ShaderDefs'
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
class PostProcessSettings
|
|
110
|
+
attr_accessor :enabled, :intensity
|
|
111
|
+
|
|
112
|
+
def initialize(enabled: true, intensity: 1.0)
|
|
113
|
+
@enabled = enabled
|
|
114
|
+
@intensity = intensity.to_f
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def type_name
|
|
118
|
+
'PostProcessSettings'
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
class Bloom
|
|
123
|
+
attr_accessor :intensity, :threshold, :soft_threshold, :composite_mode
|
|
124
|
+
|
|
125
|
+
def initialize(intensity: 0.5, threshold: 1.0, soft_threshold: 0.5, composite_mode: :additive)
|
|
126
|
+
@intensity = intensity.to_f
|
|
127
|
+
@threshold = threshold.to_f
|
|
128
|
+
@soft_threshold = soft_threshold.to_f
|
|
129
|
+
@composite_mode = composite_mode
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def type_name
|
|
133
|
+
'Bloom'
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def to_h
|
|
137
|
+
{
|
|
138
|
+
intensity: @intensity,
|
|
139
|
+
threshold: @threshold,
|
|
140
|
+
soft_threshold: @soft_threshold,
|
|
141
|
+
composite_mode: @composite_mode
|
|
142
|
+
}
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
class ChromaticAberration
|
|
147
|
+
attr_accessor :intensity, :max_samples
|
|
148
|
+
|
|
149
|
+
def initialize(intensity: 0.02, max_samples: 8)
|
|
150
|
+
@intensity = intensity.to_f
|
|
151
|
+
@max_samples = max_samples
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def type_name
|
|
155
|
+
'ChromaticAberration'
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def to_h
|
|
159
|
+
{
|
|
160
|
+
intensity: @intensity,
|
|
161
|
+
max_samples: @max_samples
|
|
162
|
+
}
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
class Vignette
|
|
167
|
+
attr_accessor :intensity, :radius, :smoothness, :color
|
|
168
|
+
|
|
169
|
+
def initialize(intensity: 0.5, radius: 0.5, smoothness: 0.5, color: nil)
|
|
170
|
+
@intensity = intensity.to_f
|
|
171
|
+
@radius = radius.to_f
|
|
172
|
+
@smoothness = smoothness.to_f
|
|
173
|
+
@color = color || Color.black
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def type_name
|
|
177
|
+
'Vignette'
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def to_h
|
|
181
|
+
{
|
|
182
|
+
intensity: @intensity,
|
|
183
|
+
radius: @radius,
|
|
184
|
+
smoothness: @smoothness,
|
|
185
|
+
color: @color.to_a
|
|
186
|
+
}
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
class FilmGrain
|
|
191
|
+
attr_accessor :intensity, :response
|
|
192
|
+
|
|
193
|
+
def initialize(intensity: 0.1, response: 0.5)
|
|
194
|
+
@intensity = intensity.to_f
|
|
195
|
+
@response = response.to_f
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def type_name
|
|
199
|
+
'FilmGrain'
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def to_h
|
|
203
|
+
{
|
|
204
|
+
intensity: @intensity,
|
|
205
|
+
response: @response
|
|
206
|
+
}
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
class Tonemapping
|
|
211
|
+
attr_accessor :mode
|
|
212
|
+
|
|
213
|
+
MODES = %i[none reinhard reinhard_luminance aces_fitted aces_approximate tony_mc_mapface blender_filmic].freeze
|
|
214
|
+
|
|
215
|
+
def initialize(mode: :tony_mc_mapface)
|
|
216
|
+
@mode = mode
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def type_name
|
|
220
|
+
'Tonemapping'
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
class ColorGrading
|
|
225
|
+
attr_accessor :exposure, :gamma, :saturation, :contrast
|
|
226
|
+
|
|
227
|
+
def initialize(exposure: 0.0, gamma: 1.0, saturation: 1.0, contrast: 1.0)
|
|
228
|
+
@exposure = exposure.to_f
|
|
229
|
+
@gamma = gamma.to_f
|
|
230
|
+
@saturation = saturation.to_f
|
|
231
|
+
@contrast = contrast.to_f
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def type_name
|
|
235
|
+
'ColorGrading'
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def to_h
|
|
239
|
+
{
|
|
240
|
+
exposure: @exposure,
|
|
241
|
+
gamma: @gamma,
|
|
242
|
+
saturation: @saturation,
|
|
243
|
+
contrast: @contrast
|
|
244
|
+
}
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
class DepthOfField
|
|
249
|
+
attr_accessor :focal_distance, :focal_length, :aperture_f_stops, :max_blur
|
|
250
|
+
|
|
251
|
+
def initialize(focal_distance: 10.0, focal_length: 50.0, aperture_f_stops: 2.8, max_blur: 0.01)
|
|
252
|
+
@focal_distance = focal_distance.to_f
|
|
253
|
+
@focal_length = focal_length.to_f
|
|
254
|
+
@aperture_f_stops = aperture_f_stops.to_f
|
|
255
|
+
@max_blur = max_blur.to_f
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def type_name
|
|
259
|
+
'DepthOfField'
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def to_h
|
|
263
|
+
{
|
|
264
|
+
focal_distance: @focal_distance,
|
|
265
|
+
focal_length: @focal_length,
|
|
266
|
+
aperture_f_stops: @aperture_f_stops,
|
|
267
|
+
max_blur: @max_blur
|
|
268
|
+
}
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
class MotionBlur
|
|
273
|
+
attr_accessor :shutter_angle, :samples
|
|
274
|
+
|
|
275
|
+
def initialize(shutter_angle: 0.5, samples: 4)
|
|
276
|
+
@shutter_angle = shutter_angle.to_f
|
|
277
|
+
@samples = samples
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def type_name
|
|
281
|
+
'MotionBlur'
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def to_h
|
|
285
|
+
{
|
|
286
|
+
shutter_angle: @shutter_angle,
|
|
287
|
+
samples: @samples
|
|
288
|
+
}
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
class Fxaa
|
|
293
|
+
attr_accessor :enabled, :edge_threshold, :edge_threshold_min
|
|
294
|
+
|
|
295
|
+
def initialize(enabled: true, edge_threshold: :high, edge_threshold_min: :high)
|
|
296
|
+
@enabled = enabled
|
|
297
|
+
@edge_threshold = edge_threshold
|
|
298
|
+
@edge_threshold_min = edge_threshold_min
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def type_name
|
|
302
|
+
'Fxaa'
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
class Smaa
|
|
307
|
+
attr_accessor :preset
|
|
308
|
+
|
|
309
|
+
PRESETS = %i[low medium high ultra].freeze
|
|
310
|
+
|
|
311
|
+
def initialize(preset: :high)
|
|
312
|
+
@preset = preset
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def type_name
|
|
316
|
+
'Smaa'
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
end
|
data/lib/bevy/shape.rb
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bevy
|
|
4
|
+
module Shape
|
|
5
|
+
class Rectangle
|
|
6
|
+
attr_reader :width, :height, :color
|
|
7
|
+
|
|
8
|
+
def initialize(width:, height:, color: Color.white)
|
|
9
|
+
@width = width.to_f
|
|
10
|
+
@height = height.to_f
|
|
11
|
+
@color = color
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_sprite
|
|
15
|
+
Sprite.new(
|
|
16
|
+
color: @color,
|
|
17
|
+
custom_size: Vec2.new(@width, @height)
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def type_name
|
|
22
|
+
'Shape::Rectangle'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class Circle
|
|
27
|
+
attr_reader :radius, :color, :segments
|
|
28
|
+
|
|
29
|
+
def initialize(radius:, color: Color.white, segments: 32)
|
|
30
|
+
@radius = radius.to_f
|
|
31
|
+
@color = color
|
|
32
|
+
@segments = segments
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def diameter
|
|
36
|
+
@radius * 2.0
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def to_sprite
|
|
40
|
+
Sprite.new(
|
|
41
|
+
color: @color,
|
|
42
|
+
custom_size: Vec2.new(diameter, diameter)
|
|
43
|
+
)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def type_name
|
|
47
|
+
'Shape::Circle'
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class Line
|
|
52
|
+
attr_reader :start_point, :end_point, :thickness, :color
|
|
53
|
+
|
|
54
|
+
def initialize(start_point:, end_point:, thickness: 2.0, color: Color.white)
|
|
55
|
+
@start_point = start_point
|
|
56
|
+
@end_point = end_point
|
|
57
|
+
@thickness = thickness.to_f
|
|
58
|
+
@color = color
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def length
|
|
62
|
+
dx = @end_point.x - @start_point.x
|
|
63
|
+
dy = @end_point.y - @start_point.y
|
|
64
|
+
Math.sqrt(dx * dx + dy * dy)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def angle
|
|
68
|
+
dx = @end_point.x - @start_point.x
|
|
69
|
+
dy = @end_point.y - @start_point.y
|
|
70
|
+
Math.atan2(dy, dx)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def center
|
|
74
|
+
Vec2.new(
|
|
75
|
+
(@start_point.x + @end_point.x) / 2.0,
|
|
76
|
+
(@start_point.y + @end_point.y) / 2.0
|
|
77
|
+
)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def to_sprite
|
|
81
|
+
Sprite.new(
|
|
82
|
+
color: @color,
|
|
83
|
+
custom_size: Vec2.new(length, @thickness)
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def to_transform(z: 0.0)
|
|
88
|
+
center_point = center
|
|
89
|
+
Transform.new(
|
|
90
|
+
translation: Vec3.new(center_point.x, center_point.y, z),
|
|
91
|
+
rotation: Quat.from_rotation_z(angle),
|
|
92
|
+
scale: Vec3.one
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def type_name
|
|
97
|
+
'Shape::Line'
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
class Polygon
|
|
102
|
+
attr_reader :points, :color
|
|
103
|
+
|
|
104
|
+
def initialize(points:, color: Color.white)
|
|
105
|
+
@points = points
|
|
106
|
+
@color = color
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def centroid
|
|
110
|
+
return Vec2.zero if @points.empty?
|
|
111
|
+
|
|
112
|
+
sum_x = @points.sum(&:x)
|
|
113
|
+
sum_y = @points.sum(&:y)
|
|
114
|
+
Vec2.new(sum_x / @points.length, sum_y / @points.length)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def bounding_box
|
|
118
|
+
return { min: Vec2.zero, max: Vec2.zero } if @points.empty?
|
|
119
|
+
|
|
120
|
+
min_x = @points.map(&:x).min
|
|
121
|
+
max_x = @points.map(&:x).max
|
|
122
|
+
min_y = @points.map(&:y).min
|
|
123
|
+
max_y = @points.map(&:y).max
|
|
124
|
+
|
|
125
|
+
{ min: Vec2.new(min_x, min_y), max: Vec2.new(max_x, max_y) }
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def to_sprite
|
|
129
|
+
bbox = bounding_box
|
|
130
|
+
width = bbox[:max].x - bbox[:min].x
|
|
131
|
+
height = bbox[:max].y - bbox[:min].y
|
|
132
|
+
|
|
133
|
+
Sprite.new(
|
|
134
|
+
color: @color,
|
|
135
|
+
custom_size: Vec2.new(width, height)
|
|
136
|
+
)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def type_name
|
|
140
|
+
'Shape::Polygon'
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
class RegularPolygon
|
|
145
|
+
attr_reader :radius, :sides, :color
|
|
146
|
+
|
|
147
|
+
def initialize(radius:, sides:, color: Color.white)
|
|
148
|
+
@radius = radius.to_f
|
|
149
|
+
@sides = [sides.to_i, 3].max
|
|
150
|
+
@color = color
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def points
|
|
154
|
+
(0...@sides).map do |i|
|
|
155
|
+
angle = (2.0 * Math::PI * i / @sides) - (Math::PI / 2.0)
|
|
156
|
+
Vec2.new(
|
|
157
|
+
@radius * Math.cos(angle),
|
|
158
|
+
@radius * Math.sin(angle)
|
|
159
|
+
)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def to_sprite
|
|
164
|
+
Sprite.new(
|
|
165
|
+
color: @color,
|
|
166
|
+
custom_size: Vec2.new(@radius * 2, @radius * 2)
|
|
167
|
+
)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def type_name
|
|
171
|
+
'Shape::RegularPolygon'
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
class Triangle < RegularPolygon
|
|
176
|
+
def initialize(radius:, color: Color.white)
|
|
177
|
+
super(radius: radius, sides: 3, color: color)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def type_name
|
|
181
|
+
'Shape::Triangle'
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
class Hexagon < RegularPolygon
|
|
186
|
+
def initialize(radius:, color: Color.white)
|
|
187
|
+
super(radius: radius, sides: 6, color: color)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def type_name
|
|
191
|
+
'Shape::Hexagon'
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|