ParticleEmitter

class pygamelib.gfx.particles.ParticleEmitter(emitter_properties=None)

Bases: PglBaseObject

The particle emitter is a key piece of the pygamelib’s particle system: it’s the part that actually do something!

The emitter takes care of managing the particles’ life cycle. It emits, move, apply forces, update and draw particles on screen. It also provide convenient methods to manage the particle pool or apply forces to all active particles in the pool.

Particle emitters are configured with EmitterProperties. This is a convenient way to place multiple emitters with the same configuration. For example, if you create a “torch fire” emitter, you can use the same properties to create multiple emitters. It’s less cumbersome than having the parameters tied to an instance of the emitter.

Here is an example of that taken from examples/benchmark-particle-system:

Example:

# The torch fire properties
emt_props = particles.EmitterProperties(
    screen.vcenter, # Position is not important as it will be updated by the
    screen.hcenter, # ParticleEmitter.render_to_buffer method.
    lifespan=150,
    variance=0.3,
    emit_number=10,
    emit_rate=0.1,
    particle=particles.ColorPartitionParticle(
        start_color=core.Color(45, 151, 227),
        stop_color=core.Color(7, 2, 40),
    ),
    particle_lifespan=5,
    radius=0.4,
)
# Now create multiple emitters at different position with the same properties.
for c in [[20, 24], [20, 35], [20, 122], [20, 133]]:
    bench_state.particle_emitters.append(particles.CircleEmitter(emt_props))
    screen.place(
        bench_state.particle_emitters[-1],
        screen.vcenter - int(bench_state.altar_sprite.height / 2) + c[0],
        c[1],
        2, # Always set your emitters to be rendered on the second pass.
    )

Important

The entire particle system is build around the Screen Buffer system and is completely incompatible with the direct display system. If you want to use the particle system you have to use Screen.place() and the other methods of the Screen Buffer system.

An emitter should always be placed on screen and set to render on the second rendering pass.

It is important if you want to avoid artifacts (like particles being rendered only under the position of the emitter).

The particles by themselves are not able to render on screen, the emitter is doing that job for them.

It also means that the particles are rendered and displayed over a screen that is already rendered. Therefor, by default and for the moment, they cannot interact with elements on screen or items in a board. It also means that there is no built in particle physics (for the moment).

__init__(emitter_properties=None) None

The constructor takes the following parameter:

Parameters:

emitter_properties (EmitterProperties) – The properties of that particle emitter.

Methods

__init__([emitter_properties])

The constructor takes the following parameter:

apply_force(force)

Apply a force to all alive particles.

attach(observer)

Attach an observer to this instance.

detach(observer)

Detach an observer from this instance.

emit([amount])

Emit a certain amount of particles.

finished()

Returns True if the emitter is finished.

handle_notification(subject[, attribute, value])

A virtual method that needs to be implemented by the observer.

load(data)

Load a particle emitter from serialized data.

notify([modifier, attribute, value])

Notify all the observers that a change occurred.

render_to_buffer(buffer, row, column, ...)

Render all the particles of that emitter in the frame buffer.

resize_pool([new_size])

In substance, this method is an alias for ParticleEmitter.particle_pool.resize().

serialize()

Serialize the particle emitter.

store_screen_position(row, column)

Store the screen position of the object.

toggle_active()

Toggle the emitter's state between active and inactive.

update()

Update all the particles in the pool.

Attributes

active

Access and set the active property.

column

Access and set the column property (i.e: x).

particle_pool

This property holds this emitter's instance of a ParticlePool.

row

Access and set the row property (i.e: y).

screen_column

A property to get/set the screen column.

screen_row

A property to get/set the screen row.

x

Access and set the x property (i.e: column).

y

Access and set the y property (i.e: row).

property active

Access and set the active property.

An emitter only emits particles if he is active. Emitted particles keeps being updated even if the emitter is not active anymore, for obvious reasons.

apply_force(force: Vector2D)

Apply a force to all alive particles.

The force needs to be a Vector2D.

Parameters:

force (Vector2D) – The force to apply to the particles.

Example:

my_emitter.apply_force(base.Vector2D(0,0.3)) # slight wind.
attach(observer)

Attach an observer to this instance. It means that until it is detached, it will be notified every time that a notification is issued (usually on changes).

An object cannot add itself to the list of observers (to avoid infinite recursions).

Parameters:

observer (PglBaseObject) – An observer to attach to this object.

Returns:

True or False depending on the success of the operation.

Return type:

bool

Example:

myboard = Board()
screen = Game.instance().screen
# screen will be notified of all changes in myboard
myboard.attach(screen)
property column

Access and set the column property (i.e: x).

detach(observer)

Detach an observer from this instance. If observer is not in the list this returns False.

Parameters:

observer (PglBaseObject) – An observer to detach from this object.

Returns:

True or False depending on the success of the operation.

Return type:

bool

Example:

# screen will no longer be notified of the changes in myboard.
myboard.detach(screen)
emit(amount: int = None) None

Emit a certain amount of particles.

The emitter will request particles from the particle pool. This in turn will trigger the recycling of dead particles if needed.

Calling this method faster than the configured emit_rate is not going to emit more particles. An emitter cannot emit particles faster than its emit_rate.

If amount is None, the emitter emits emit_number particles.

Parameters:

amount (int) – The amount (number) of particles to be emitted.

Example:

my_emitter.emit(50)
finished()

Returns True if the emitter is finished.

A finished emitter has both:

  • Reach the end of its lifespan (i.e lifespan == 0)

  • And all particles are finished too.

This means that an emitter will, in most cases, not be finished as soon as its lifespan reaches 0 but a bit after. When all of its managed particles are dead.

This is on purpose for both aesthetic reasons (avoiding particles sudden removal) and for optimization (counting active particles is a O(n) operation and can be very long when there’s a lot of particles so we want to do it only when necessary).

Example:

if my_emitter.finished():
        screen.delete(my_emitter.row, my_emitter.column)
handle_notification(subject, attribute=None, value=None)

A virtual method that needs to be implemented by the observer. By default it does nothing but each observer needs to implement it if something needs to be done when notified.

This method always receive the notifying object as first parameter. The 2 other parameters are optional and can be None.

You can use the attribute and value as you see fit. You are free to consider attribute as an event and value as the event’s value.

Parameters:
  • subject (PglBaseObject) – The object that has changed.

  • attribute (str) – The attribute that has changed, it is usually a “FQDN style” string. This can be None.

  • value (Any) – The new value of the attribute. This can be None.

classmethod load(data)

Load a particle emitter from serialized data.

Parameters:

data (dict) – The serialized data.

Returns:

The loaded particle emitter.

Return type:

ParticleEmitter

notify(modifier=None, attribute: str = None, value: Any = None) None

Notify all the observers that a change occurred.

Parameters:
  • modifier (PglBaseObject) – An optional parameter that identify the modifier object to exclude it from the notified objects.

  • attribute (str) – An optional parameter that identify the attribute that has changed.

  • value (Any) – An optional parameter that identify the new value of the attribute.

Example:

# This example is silly, you would usually notify other objects from inside
# an object that changes a value that's important for the observers.
color = Color(255,200,125)
color.attach(some_text_object)
color.notify()
property particle_pool

This property holds this emitter’s instance of a ParticlePool.

render_to_buffer(buffer, row, column, buffer_height, buffer_width)

Render all the particles of that emitter in the frame buffer.

This method is automatically called by pygamelib.engine.Screen.render().

Parameters:
  • buffer (numpy.array) – A screen buffer to render the item into.

  • row (int) – The row to render in.

  • column (int) – The column to render in.

  • height (int) – The total height of the display buffer.

  • width (int) – The total width of the display buffer.

resize_pool(new_size: int = None)

In substance, this method is an alias for ParticleEmitter.particle_pool.resize(). However, called without parameter, it will try to resize the particle pool to emit_number * particle_lifespan. It will do so only if the resulting number is greater than the current particle pool size.

Parameters:

new_size (int) – The desired new size of the pool.

Example:

my_emitter.resize_pool(3000)
property row

Access and set the row property (i.e: y).

property screen_column: int

A property to get/set the screen column.

Parameters:

value (int) – the screen column

Return type:

int

property screen_row: int

A property to get/set the screen row.

Parameters:

value (int) – the screen row

Return type:

int

serialize()

Serialize the particle emitter.

Returns:

A dictionary containing all the emitter’s properties.

Return type:

dict

store_screen_position(row: int, column: int) bool

Store the screen position of the object.

This method is automatically called by Screen.place().

Parameters:
  • row (int) – The row (or y) coordinate.

  • column (int) – The column (or x) coordinate.

Example:

an_object.store_screen_coordinate(3,8)
toggle_active()

Toggle the emitter’s state between active and inactive.

An inactive emitter does not emit new particles but keeps processing particles that have already been emitted.

Example:

if not my_emitter.active:
    my_emitter.toggle_active()
update()

Update all the particles in the pool.

Updating a particle means applying particle_acceleration to every particle and then call Particle.update().

Example:

my_emitter.update()
property x

Access and set the x property (i.e: column).

property y

Access and set the y property (i.e: row).