minigl 2.4.3 → 2.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 46eaeb260b03c9bcfbac716d7568b01c081d66760d71dc540ca9046050f7d89d
4
- data.tar.gz: 3de3cd79bd21324af047f1705d641374e92c986ec0f02badf0a5fd9206f228e8
3
+ metadata.gz: 6078cf1c0aafd790460ec6b7723dff865c0a2e78a8359fd8734cd8a6a07aec60
4
+ data.tar.gz: 61be9170370e9b912a7c3a7087ca145de121f36b005abf62bfe193ca1dc29ec3
5
5
  SHA512:
6
- metadata.gz: 33675d555bd833c359f548bff9c16ef95da819ecc084ecbc657c60016d5e3d18255cd19da03252b212e53bb8600a5a0c4c9f4ab4893261377a7f4f20a03d991b
7
- data.tar.gz: 3f9ed35d874c81bca4544a42c7f6106c0f3b26ba69bf5bfcba59f201297588be32aa6a2f697f2ea4ffde846e8f46fd2d42c5bc68142ec925cf9f8cd6bc5542cf
6
+ metadata.gz: 68d1060caaf63cfe944a924b692c38680833a15fa49412060295904e630d8b73e5b6342abf4febf1ff6d9324e88f61e0a34fa5c9014e70b376cafa10402e0df5
7
+ data.tar.gz: ff9db71adca879e4ec8b7044c1864477befb45eff207cdd0dc2b1ff3d97d4f6f3f0255e1d61e6705293d7ab3d490c484543f40cd861545cf1936b5b09d2da590
data/README.md CHANGED
@@ -10,6 +10,7 @@ It provides the following features:
10
10
  * UI (text, buttons, text fields, drop-down lists, progress bars)
11
11
  * Basic physics and collision checking
12
12
  * Animated objects
13
+ * Particle systems
13
14
 
14
15
  More functionalities are coming. Feel free to contribute! You can send feedback
15
16
  to victordavidsantos@gmail.com.
@@ -38,13 +39,17 @@ After installing the Gosu dependencies, you can just `gem install minigl`.
38
39
 
39
40
  ## Documentation
40
41
 
41
- * The library is 100% RDoc-documented [here](http://www.rubydoc.info/gems/minigl).
42
+ * The library is 100% RDoc-documented [here](https://www.rubydoc.info/gems/minigl).
42
43
  * The [wiki](https://github.com/victords/minigl/wiki) is a work in progress with tutorials and examples.
43
44
  * Test package and examples aren't complete!
44
45
 
45
- ## Version 2.4.3
46
+ ## Version 2.5.0
46
47
 
47
- * Fixed a collision checking bug in `Movement#move`.
48
+ * Added `Particles` (particle system) class. Run `test/particles_game.rb` to check its capabilities!
49
+
50
+ ### Version 2.5.1
51
+
52
+ Patch fixing the required Ruby version (>= 3.1).
48
53
 
49
54
  ## Contributing
50
55
 
@@ -0,0 +1,313 @@
1
+ module MiniGL
2
+ # A particle system.
3
+ class Particles
4
+ # Create a new particle system.
5
+ # Options:
6
+ # - x: x-coordinate of the origin of the particle system. If +source+ is
7
+ # set, it has precedence.
8
+ # - y: y-coordinate of the origin of the particle system. If +source+ is
9
+ # set, it has precedence.
10
+ # - source: if set, must be an object that responds to +x+ and +y+. The
11
+ # position of the particle system will be updated to this object's
12
+ # position on initialization and every time +update+ is called.
13
+ # - emission_interval (Integer|Range): interval in frames between each
14
+ # particle emission. It can be a fixed value or a range, in which case
15
+ # the interval will be a random value within that range (a new value
16
+ # before each emission). Default: 10.
17
+ # - emission_rate (Integer|Range): how many particles will be emitted at a
18
+ # time. It can be a fixed value or a range, in which case a random number
19
+ # of particles in that range will be emitted each time. Default: 1.
20
+ # - duration (Integer): how many frames each particle will live. Default: 30.
21
+ # - shape (Symbol|nil): one of +:square+, +:triangle_up+, or
22
+ # +:triangle_down+, to emit basic shapes (if the +img+ option is set, it
23
+ # has precedence). Shape particles don't support rotation. Either this or
24
+ # +img+ must be set.
25
+ # - img (Gosu::Image|nil): image of the particle, has precedence over
26
+ # +shape+. Either this or +shape+ must be set.
27
+ # - scale (Numeric): fixed scale of each particle, ignored if +scale_change+
28
+ # is set to a valid value. Default: 1.
29
+ # - scale_change (Symbol|nil): one of +:grow+, +:shrink+, or +:alternate+,
30
+ # indicates how the scale of the particle will change over time. +:grow+
31
+ # will cause the scale to change from +scale_min+ to +scale_max+;
32
+ # +:shrink+ will cause the scale to change from +scale_max+ to
33
+ # +scale_min+; +:alternate+ will cause the scale to first go from
34
+ # +scale_min+ to +scale_max+, in <code>scale_inflection * duration</code>
35
+ # frames, and then back to +scale_min+ in the remaining frames. All
36
+ # changes are linear over time.
37
+ # - scale_min (Numeric): minimum scale, to be used together with
38
+ # +scale_change+. Default: 0.
39
+ # - scale_max (Numeric): maximum scale, to be used together with
40
+ # +scale_change+. Default: 1.
41
+ # - scale_inflection (Numeric): should be a number between 0 and 1, to be
42
+ # used with +scale_change+ set to +:alternate+. Default: 0.5.
43
+ # - alpha (Numeric): fixed alpha of each particle, ignored if +alpha_change+
44
+ # is set to a valid value. Default: 255.
45
+ # - alpha_change, alpha_min, alpha_max, alpha_inflection: behave the same
46
+ # way as the corresponding properties for +scale+. Default +alpha_max+ is
47
+ # 255.
48
+ # - angle (Numeric|Range|nil): initial rotation angle of each particle in
49
+ # degrees. Can be a fixed value or a range, in which case the initial
50
+ # rotation will be a random value within that range. Default: nil (no
51
+ # rotation).
52
+ # - rotation(Numeric|nil): how much each particle will rotate each frame,
53
+ # in degrees. Default: nil (no rotation).
54
+ # - speed (Vector|Hash|nil): specifies how the particle will move each
55
+ # frame. It can be a +Vector+, in which case the particle will move a
56
+ # fixed amount (corresponding to the +x+ and +y+ values of the vector)
57
+ # or a +Hash+ with +:x+ and +:y+ keys, in this case the value can be
58
+ # fixed or a range, for random movement. Default: nil (no movement).
59
+ # - color (Integer): color to tint the particles, in the 0xRRGGBB format.
60
+ # Default: 0xffffff (white, no tinting).
61
+ # - round_position (Boolean): only draw particles in integer positions.
62
+ # Default: true.
63
+ def initialize(**options)
64
+ raise "Particles must have either a shape or an image!" if options[:shape].nil? && options[:img].nil?
65
+
66
+ @options = DEFAULT_OPTIONS.merge(options)
67
+ @x = @options[:source]&.x || @options[:x] || 0
68
+ @y = @options[:source]&.y || @options[:y] || 0
69
+
70
+ @particles = []
71
+ @emitting = false
72
+ end
73
+
74
+ # Starts emitting particles. This returns +self+, so you can create, start,
75
+ # and assign a particle system to a variable like this:
76
+ # <code>@p_system = Particles.new(...).start</code>
77
+ def start
78
+ set_emission_time
79
+ @timer = @emission_time
80
+ @emitting = true
81
+ self
82
+ end
83
+
84
+ # Stops emitting new particles. The existing particles will still be kept
85
+ # alive until they hit +duration+ frames.
86
+ def stop
87
+ @emitting = false
88
+ end
89
+
90
+ # Returns a boolean indicating whether this particle system is currently
91
+ # emitting particles.
92
+ def emitting?
93
+ @emitting
94
+ end
95
+
96
+ # Returns the current particle count.
97
+ def count
98
+ @particles.size
99
+ end
100
+
101
+ # Updates the particle system. This should be called in the +update+ loop
102
+ # of the game.
103
+ def update
104
+ @particles.each do |particle|
105
+ particle.update
106
+ @particles.delete(particle) if particle.dead?
107
+ end
108
+ return unless @emitting
109
+
110
+ if @options[:source]
111
+ @x = @options[:source].x
112
+ @y = @options[:source].y
113
+ end
114
+
115
+ @timer += 1
116
+ if @timer >= @emission_time
117
+ count = @options[:emission_rate].is_a?(Range) ? rand(@options[:emission_rate]) : @options[:emission_rate]
118
+ count.times do
119
+ x = @options[:area] ? @x + rand * @options[:area].x : @x + @options[:spread] * (rand - 0.5)
120
+ y = @options[:area] ? @y + rand * @options[:area].y : @y + @options[:spread] * (rand - 0.5)
121
+ @particles << Particle.new(x:,
122
+ y:,
123
+ duration: @options[:duration],
124
+ shape: @options[:shape],
125
+ img: @options[:img],
126
+ **@options.slice(*PARTICLE_OPTIONS))
127
+ end
128
+ set_emission_time
129
+ @timer = 0
130
+ end
131
+ end
132
+
133
+ # Draws the particles.
134
+ # Parameters:
135
+ # - map (Map|nil): a map whose camera will be used to determine the
136
+ # position of particles in the screen.
137
+ # - z_index (Integer): z-index to draw the particles. Default: 0.
138
+ def draw(map = nil, z_index = 0)
139
+ @particles.each do |particle|
140
+ particle.draw(map, z_index)
141
+ end
142
+ end
143
+
144
+ private
145
+
146
+ # :nodoc:
147
+ DEFAULT_OPTIONS = {
148
+ x: 0,
149
+ y: 0,
150
+ source: nil,
151
+ emission_interval: 10,
152
+ emission_rate: 1,
153
+ duration: 30,
154
+ shape: nil,
155
+ img: nil,
156
+ spread: 0,
157
+ scale: 1,
158
+ scale_change: nil,
159
+ scale_min: 0,
160
+ scale_max: 1,
161
+ scale_inflection: 0.5,
162
+ alpha: 255,
163
+ alpha_change: nil,
164
+ alpha_min: 0,
165
+ alpha_max: 255,
166
+ alpha_inflection: 0.5,
167
+ angle: nil,
168
+ rotation: nil,
169
+ speed: nil,
170
+ color: 0xffffff,
171
+ round_position: true,
172
+ }.freeze
173
+
174
+ # :nodoc:
175
+ PARTICLE_OPTIONS = %i[
176
+ scale
177
+ scale_change
178
+ scale_min
179
+ scale_max
180
+ scale_inflection
181
+ alpha
182
+ alpha_change
183
+ alpha_min
184
+ alpha_max
185
+ alpha_inflection
186
+ angle
187
+ rotation
188
+ speed
189
+ color
190
+ round_position
191
+ ].freeze
192
+
193
+ def set_emission_time # :nodoc:
194
+ interval = @options[:emission_interval]
195
+ @emission_time = interval.is_a?(Range) ? rand(interval) : interval
196
+ end
197
+
198
+ class Particle # :nodoc:
199
+ def initialize(x:, y:, duration:, shape: nil, img: nil, **options)
200
+ @x = x
201
+ @y = y
202
+ @duration = duration
203
+ @shape = shape
204
+ @img = img
205
+ @options = DEFAULT_OPTIONS.slice(*PARTICLE_OPTIONS).merge(options)
206
+ @elapsed_time = 0
207
+
208
+ if @options[:angle].is_a?(Range)
209
+ @angle = rand(@options[:angle])
210
+ elsif @options[:angle].is_a?(Numeric)
211
+ @angle = @options[:angle]
212
+ end
213
+
214
+ if @options[:speed].is_a?(Hash)
215
+ speed_x = @options[:speed][:x].is_a?(Range) ? rand(@options[:speed][:x]) : (@options[:speed][:x] || 0)
216
+ speed_y = @options[:speed][:y].is_a?(Range) ? rand(@options[:speed][:y]) : (@options[:speed][:y] || 0)
217
+ @speed = Vector.new(speed_x, speed_y)
218
+ elsif @options[:speed].is_a?(Vector)
219
+ @speed = @options[:speed]
220
+ end
221
+
222
+ init_variable_property(:scale)
223
+ init_variable_property(:alpha)
224
+ end
225
+
226
+ def init_variable_property(name)
227
+ ivar_name = "@#{name}".to_sym
228
+ case @options["#{name}_change".to_sym]
229
+ when :grow, :alternate
230
+ instance_variable_set(ivar_name, @options["#{name}_min".to_sym])
231
+ when :shrink
232
+ instance_variable_set(ivar_name, @options["#{name}_max".to_sym])
233
+ else
234
+ instance_variable_set(ivar_name, @options[name.to_sym])
235
+ end
236
+ end
237
+
238
+ def update_variable_property(name)
239
+ ivar_name = "@#{name}".to_sym
240
+ min = @options["#{name}_min".to_sym]
241
+ max = @options["#{name}_max".to_sym]
242
+ case @options["#{name}_change".to_sym]
243
+ when :grow
244
+ instance_variable_set(ivar_name, min + (@elapsed_time.to_f / @duration) * (max - min))
245
+ when :shrink
246
+ instance_variable_set(ivar_name, max - (@elapsed_time.to_f / @duration) * (max - min))
247
+ when :alternate
248
+ inflection_point = (@options["#{name}_inflection".to_sym] * @duration).round
249
+ if @elapsed_time >= inflection_point
250
+ instance_variable_set(ivar_name, min + (@duration - @elapsed_time).to_f / (@duration - inflection_point) * (max - min))
251
+ else
252
+ instance_variable_set(ivar_name, min + (@elapsed_time.to_f / inflection_point) * (max - min))
253
+ end
254
+ end
255
+ end
256
+
257
+ def dead?
258
+ @elapsed_time >= @duration
259
+ end
260
+
261
+ def update
262
+ if @options[:rotation] && !@img.nil?
263
+ @angle = 0 if @angle.nil?
264
+ @angle += @options[:rotation]
265
+ @angle -= 360 if @angle >= 360
266
+ end
267
+
268
+ if @speed
269
+ @x += @speed.x
270
+ @y += @speed.y
271
+ end
272
+
273
+ update_variable_property(:scale) if @options[:scale_change]
274
+ if @options[:alpha_change]
275
+ update_variable_property(:alpha)
276
+ @alpha = @alpha.round
277
+ end
278
+
279
+ @elapsed_time += 1
280
+ end
281
+
282
+ def draw(map, z_index)
283
+ x = @x - (map&.cam&.x || 0)
284
+ y = @y - (map&.cam&.y || 0)
285
+ if @options[:round_position]
286
+ x = x.round
287
+ y = y.round
288
+ end
289
+ color = (@alpha << 24) | @options[:color]
290
+ if @img
291
+ if @angle
292
+ @img.draw_rot(x, y, z_index, @angle, 0.5, 0.5, @scale, @scale, color)
293
+ else
294
+ @img.draw(x - @img.width * @scale * 0.5, y - @img.height * @scale * 0.5, z_index, @scale, @scale, color)
295
+ end
296
+ else
297
+ case @shape
298
+ when :square
299
+ G.window.draw_rect(@x - @scale * 0.5, @y - @scale * 0.5, @scale, @scale, color, z_index)
300
+ when :triangle_up
301
+ G.window.draw_triangle(@x - @scale * 0.5, @y + @scale * 0.433, color,
302
+ @x + @scale * 0.5, @y + @scale * 0.433, color,
303
+ @x, @y - @scale * 0.433, color, z_index)
304
+ when :triangle_down
305
+ G.window.draw_triangle(@x - @scale * 0.5, @y - @scale * 0.433, color,
306
+ @x + @scale * 0.5, @y - @scale * 0.433, color,
307
+ @x, @y + @scale * 0.433, color, z_index)
308
+ end
309
+ end
310
+ end
311
+ end
312
+ end
313
+ end
data/lib/minigl.rb CHANGED
@@ -3,3 +3,4 @@ require_relative 'minigl/map'
3
3
  require_relative 'minigl/text'
4
4
  require_relative 'minigl/forms'
5
5
  require_relative 'minigl/localization'
6
+ require_relative 'minigl/particles'
@@ -0,0 +1,70 @@
1
+ require_relative '../lib/minigl'
2
+
3
+ include MiniGL
4
+
5
+ class MyGame < GameWindow
6
+ class Source
7
+ attr_accessor :x, :y
8
+
9
+ def initialize(x, y)
10
+ @x = x
11
+ @y = y
12
+ end
13
+ end
14
+
15
+ def initialize
16
+ super(800, 600, false)
17
+ @source = Source.new(100, 100)
18
+ @particles_systems = [
19
+ Particles.new(
20
+ source: @source,
21
+ img: Res.img(:square),
22
+ duration: 30,
23
+ spread: 50,
24
+ emission_rate: 5,
25
+ color: 0x00ffff,
26
+ scale_change: :grow,
27
+ alpha_change: :shrink,
28
+ speed: { x: -1..1, y: -2..2 },
29
+ rotation: 1,
30
+ angle: 0..89
31
+ ),
32
+ Particles.new(
33
+ x: 400,
34
+ y: 100,
35
+ shape: :triangle_down,
36
+ spread: 50,
37
+ emission_interval: 8,
38
+ emission_rate: 1..3,
39
+ scale: 40,
40
+ color: 0xffff00,
41
+ alpha_change: :alternate,
42
+ ),
43
+ ]
44
+ @particles_systems.each(&:start)
45
+ end
46
+
47
+ def update
48
+ KB.update
49
+ @source.x -= 3 if KB.key_down?(Gosu::KB_LEFT)
50
+ @source.x += 3 if KB.key_down?(Gosu::KB_RIGHT)
51
+ @source.y -= 3 if KB.key_down?(Gosu::KB_UP)
52
+ @source.y += 3 if KB.key_down?(Gosu::KB_DOWN)
53
+
54
+ if KB.key_pressed?(Gosu::KB_SPACE)
55
+ if @particles_systems[1].emitting?
56
+ @particles_systems[1].stop
57
+ else
58
+ @particles_systems[1].start
59
+ end
60
+ end
61
+
62
+ @particles_systems.each(&:update)
63
+ end
64
+
65
+ def draw
66
+ @particles_systems.each(&:draw)
67
+ end
68
+ end
69
+
70
+ MyGame.new.show
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minigl
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.3
4
+ version: 2.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor David Santos
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-30 00:00:00.000000000 Z
11
+ date: 2023-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gosu
@@ -46,6 +46,7 @@ files:
46
46
  - lib/minigl/localization.rb
47
47
  - lib/minigl/map.rb
48
48
  - lib/minigl/movement.rb
49
+ - lib/minigl/particles.rb
49
50
  - lib/minigl/text.rb
50
51
  - test/collision.rb
51
52
  - test/data/font/font1.ttf
@@ -82,6 +83,7 @@ files:
82
83
  - test/map_tests.rb
83
84
  - test/mov_game.rb
84
85
  - test/movement_tests.rb
86
+ - test/particles_game.rb
85
87
  - test/res_tests.rb
86
88
  - test/test.png
87
89
  - test/vector_tests.rb
@@ -97,14 +99,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
97
99
  requirements:
98
100
  - - ">="
99
101
  - !ruby/object:Gem::Version
100
- version: '2.0'
102
+ version: '3.1'
101
103
  required_rubygems_version: !ruby/object:Gem::Requirement
102
104
  requirements:
103
105
  - - ">="
104
106
  - !ruby/object:Gem::Version
105
107
  version: '0'
106
108
  requirements: []
107
- rubygems_version: 3.2.15
109
+ rubygems_version: 3.4.10
108
110
  signing_key:
109
111
  specification_version: 4
110
112
  summary: MiniGL
@@ -117,6 +119,7 @@ test_files:
117
119
  - test/map_tests.rb
118
120
  - test/mov_game.rb
119
121
  - test/movement_tests.rb
122
+ - test/particles_game.rb
120
123
  - test/res_tests.rb
121
124
  - test/vector_tests.rb
122
125
  - test/test.png