Class: MiniGL::Particles

Inherits:
Object
  • Object
show all
Defined in:
lib/minigl/particles.rb

Overview

A particle system.

Defined Under Namespace

Classes: Particle

Instance Method Summary collapse

Constructor Details

#initialize(**options) ⇒ Particles

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.



68
69
70
71
72
73
74
75
76
77
# 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

Instance Method Details

#countObject

Returns the current particle count.



108
109
110
# File 'lib/minigl/particles.rb', line 108

def count
  @particles.size
end

#draw(map = nil, z_index = 0) ⇒ Object

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.



149
150
151
152
153
# 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?Boolean

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

Returns:

  • (Boolean)


103
104
105
# File 'lib/minigl/particles.rb', line 103

def emitting?
  @emitting
end

#move_to(x, y) ⇒ Object

Changes particle system origin to (x, y).



96
97
98
99
# File 'lib/minigl/particles.rb', line 96

def move_to(x, y)
  @x = x
  @y = y
end

#startObject

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



82
83
84
85
86
87
# File 'lib/minigl/particles.rb', line 82

def start
  set_emission_time
  @timer = @emission_time
  @emitting = true
  self
end

#stopObject

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



91
92
93
# File 'lib/minigl/particles.rb', line 91

def stop
  @emitting = false
end

#updateObject

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



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# 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