class MiniGL::Particles

A particle system.

Public Class Methods

new(**options) click to toggle source

Create a new particle system. Options:

  • x (Numeric): x-coordinate of the origin of the particle system. If source is set, it has precedence.

  • y (Numeric): y-coordinate of the origin of the particle system. If source is set, it has precedence.

  • source: if set, must be an object that responds to x and y. The position of the particle system will be updated to (source.x + source_offset_x, source.y + source_offset_y) on initialization and every time update is called.

  • source_offset_x (Numeric): horizontal offset relative to the source where the particle system will be positioned. Default: 0.

  • source_offset_y (Numeric): vertical offset relative to the source where the particle system will be positioned. Default: 0.

  • emission_interval (Integer|Range): interval in frames between each particle emission. It can be a fixed value or a range, in which case the interval will be a random value within that range (a new value before each emission). Default: 10.

  • emission_rate (Integer|Range): how many particles will be emitted at a time. It can be a fixed value or a range, in which case a random number of particles in that range will be emitted each time. Default: 1.

  • duration (Integer): how many frames each particle will live. Default: 30.

  • shape (Symbol|nil): one of :square, :triangle_up, or :triangle_down, to emit basic shapes (if the img option is set, it has precedence). Shape particles don’t support rotation. Either this or img must be set.

  • img (Gosu::Image|nil): image of the particle, has precedence over shape. Either this or shape must be set.

  • scale (Numeric): fixed scale of each particle, ignored if scale_change is set to a valid value. Default: 1.

  • scale_change (Symbol|nil): one of :grow, :shrink, or :alternate, indicates how the scale of the particle will change over time. :grow will cause the scale to change from scale_min to scale_max; :shrink will cause the scale to change from scale_max to scale_min; :alternate will cause the scale to first go from scale_min to scale_max, in scale_inflection * duration frames, and then back to scale_min in the remaining frames. All changes are linear over time.

  • scale_min (Numeric): minimum scale, to be used together with scale_change. Default: 0.

  • scale_max (Numeric): maximum scale, to be used together with scale_change. Default: 1.

  • scale_inflection (Numeric): should be a number between 0 and 1, to be used with scale_change set to :alternate. Default: 0.5.

  • alpha (Numeric): fixed alpha of each particle, ignored if alpha_change is set to a valid value. Default: 255.

  • alpha_change, alpha_min, alpha_max, alpha_inflection: behave the same way as the corresponding properties for scale. Default alpha_max is 255.

  • angle (Numeric|Range|nil): initial rotation angle of each particle in degrees. Can be a fixed value or a range, in which case the initial rotation will be a random value within that range. Default: nil (no rotation).

  • rotation(Numeric|nil): how much each particle will rotate each frame, in degrees. Default: nil (no rotation).

  • speed (Vector|Hash|nil): specifies how the particle will move each frame. It can be a Vector, in which case the particle will move a fixed amount (corresponding to the x and y values of the vector) or a Hash with :x and :y keys, in this case the value can be fixed or a range, for random movement. Default: nil (no movement).

  • color (Integer): color to tint the particles, in the 0xRRGGBB format. Default: 0xffffff (white, no tinting).

  • round_position (Boolean): only draw particles in integer positions. Default: true.

# File lib/minigl/particles.rb, line 68
def initialize(**options)
  raise "Particles must have either a shape or an image!" if options[:shape].nil? && options[:img].nil?

  @options = DEFAULT_OPTIONS.merge(options)
  @x = (@options[:source]&.x || @options[:x]) + @options[:source_offset_x]
  @y = (@options[:source]&.y || @options[:y]) + @options[:source_offset_y]

  @particles = []
  @emitting = false
end

Public Instance Methods

count() click to toggle source

Returns the current particle count.

# File lib/minigl/particles.rb, line 108
def count
  @particles.size
end
draw(map = nil, z_index = 0) click to toggle source

Draws the particles. Parameters:

  • map (Map|nil): a map whose camera will be used to determine the position of particles in the screen.

  • z_index (Integer): z-index to draw the particles. Default: 0.

# File lib/minigl/particles.rb, line 149
def draw(map = nil, z_index = 0)
  @particles.each do |particle|
    particle.draw(map, z_index)
  end
end
emitting?() click to toggle source

Returns a boolean indicating whether this particle system is currently emitting particles.

# File lib/minigl/particles.rb, line 103
def emitting?
  @emitting
end
move_to(x, y) click to toggle source

Changes particle system origin to (x, y).

# File lib/minigl/particles.rb, line 96
def move_to(x, y)
  @x = x
  @y = y
end
start() click to toggle source

Starts emitting particles. This returns self, so you can create, start, and assign a particle system to a variable like this: @p_system = Particles.new(...).start

# File lib/minigl/particles.rb, line 82
def start
  set_emission_time
  @timer = @emission_time
  @emitting = true
  self
end
stop() click to toggle source

Stops emitting new particles. The existing particles will still be kept alive until they hit duration frames.

# File lib/minigl/particles.rb, line 91
def stop
  @emitting = false
end
update() click to toggle source

Updates the particle system. This should be called in the update loop of the game.

# File lib/minigl/particles.rb, line 114
def update
  @particles.each do |particle|
    particle.update
    @particles.delete(particle) if particle.dead?
  end
  return unless @emitting

  if @options[:source]
    @x = @options[:source].x + @options[:source_offset_x]
    @y = @options[:source].y + @options[:source_offset_y]
  end

  @timer += 1
  if @timer >= @emission_time
    count = @options[:emission_rate].is_a?(Range) ? rand(@options[:emission_rate]) : @options[:emission_rate]
    count.times do
      x = @options[:area] ? @x + rand * @options[:area].x : @x + @options[:spread] * (rand - 0.5)
      y = @options[:area] ? @y + rand * @options[:area].y : @y + @options[:spread] * (rand - 0.5)
      @particles << Particle.new(x:,
                                 y:,
                                 duration: @options[:duration],
                                 shape: @options[:shape],
                                 img: @options[:img],
                                 **@options.slice(*PARTICLE_OPTIONS))
    end
    set_emission_time
    @timer = 0
  end
end