The ParticleEmitter Object - Grisgram/gml-raptor GitHub Wiki
There is also an object available in raptor
, which you can put directly on a layer in your room, the ParticleEmitter
.
It can be found in the _gml_raptor_/Objects
folder of the project template.
This object is also used by the ParticleManager
when you create or clone additional emitters in your scene. Read more about this in Multiple Emitters.
The object offers a range of variables to set at design time in the room editor or at runtime.
When you create or clone an emitter, the methods of the ParticleManager
take care about the details here.
Variable | Type | Description |
---|---|---|
partsys_index |
integer | If you read the documentation to this point, you very likely already know, that this is either undefined if you have only one layer to render particles, or that this is the index for the PARTSYS macro and the index you set in the Particle Editor when you created your particle effect |
follow_instance |
object instance | Set this pointer to any instance in your room, to make the emitter follow that instance |
follow_offset |
Coord2 | Set the offset (x and y) the emitter shall keep to the instance it follows |
scale_with_instance |
bool | More often than not your instances might change their size/scaling during their lifetime. Set this to true to have the emitter also scale with the instance in the scene |
emitter_name |
string | The unique name of the emitter |
stream_on_create |
bool | True, if this emitter shall start streaming particles immediately when created. Default = false |
stream_start_delay |
real | The number of frames to wait, before actually streaming |
stream_particle_name |
string | In the Particle Editor you set a default particle for an emitter, however, when you add an emitter manually to the scene, the emitter doesn't know about that default, so you have to set the name of the particle type to spread here |
stream_particle_count |
integer | The particles per frame to emit in streaming mode |
burst_particle_name |
string | Same as with stream_particle_name, the manually added object has no information about the default particle name |
burst_particle_count |
integer | The number of particles to burst in one go |
When you try to attach your emitter to an instance for the very first time, you will recognize, that the emitter is placed exactly at the x/y
coordinates of its parent (the instance it follows).
Even if this is a natural default, in most cases, you will not want the emitter to spread exactly at this coordinates. You will want an offset to the parent. Imagine the thrust beam of a space ship. If the ship is flying to the right, you will likely want the beam to appear in the middle of the ship (vertically) and on its left edge (behind the ship, horizontally).
A toch flame will likely not spread in the top left corner of the torch, but more in the center of the object.
These offsets are very specific, spezialized for each single object.
Follow instance works as a delta mechanism, means, that, if the parent moved 5 pixels to left, the emitter will also move 5 pixels to the left.
Knowing this, makes defining the offset very easy:
After attaching an emitter to an instance, just set the emitter position!
Here's an example (The example uses the raptor
macros for edges of instances, so you also see a good usage scenario for them here):
Note
This example shows the very basic "all-manually" way of attaching an emitter. There are much better ways to do this as you will see in the examples below this one!
Also, this example does not use object pools. To be honest, this example shows kind of a way "how to not do it". Keep that in mind, as negative examples also help you understanding, how to do it right.
var ship = instance_create_layer(VIEW_CENTER_X, VIEW_CENTER_Y, "ShipLayer", SpaceShip);
var ship_left, ship_middle;
with(ship) {
ship_left = SELF_VIEW_LEFT_EDGE;
ship_middle = SELF_VIEW_CENTER_Y;
}
var emitter = instance_create_layer(VIEW_CENTER_X, VIEW_CENTER_Y, "BeamLayer", ParticleEmitter);
with(emitter) {
follow_instance = ship;
x = ship_left;
y = ship_middle;
scale_with_instance = true;
stream_particle_name = "ptThrustBeam";
stream_on_create = true;
stream_particle_count = 2;
stream_start_delay = 0;
}
Now, that's quite some code needed to make a beam follow the ship... This can't be a good way, right? If raptor only had this option, I'd not use it.
Let's take a look at how to do it right:
Back to the Particle Editor, the object pools and the available methods in the ParticleManager class. What do we know?
- We know, that we created a particle emitter in the Particle Editor when we exported our code
- We also created a particle type when we exported
- We already set the partsys_index at export time
- We have a
ParticleManager
ready to use through thePARTSYS
macro - Now we just want the predefined emitter to follow our space ship
- AND we want to use the object pools for performance
Note
Adding all this up, it is clear, that the first example above does everything wrong!
In the Create
and Clean Up
events of your spaceship, write this:
// Create
beam_emitter = PARTSYS.emitter_attach_clone("emThrustBeam", self);
beam_emitter.set_offset(SELF_LEFT_EDGE, SELF_CENTER_Y);
// Clean Up
pool_return_instance(beam_emitter);
For this example, we assume, that your derived emitter object is named ThrustEmitter
.
The set_emitter_object
and reset_emitter_object
pair of calls is something you should be used to, as it is a common GameMaker pattern, which can also be found as method pairs of shader_set
and shader_reset
, same for surfaces, fonts (draw_set_font
) and so on.
You only have to add such a pair of calls around the creation of your emitter, and you are done:
// Create
PARTSYS.set_emitter_object(ThrustEmitter);
beam_emitter = PARTSYS.emitter_attach_clone("emThrustBeam", self);
beam_emitter.set_offset(SELF_LEFT_EDGE, SELF_CENTER_Y);
PARTSYS.reset_emitter_object();
// Clean Up
pool_return_instance(beam_emitter);
Note
Now, THAT looks way better, right?
This is the way how to do it! The beam will follow the ship at a set offset for as long as it is in the scene.
In the example above you have seen the very handy set_offset
function of the ParticleEmitter
.
It also offers functions for streaming, bursting and stop of streaming.
Once you have an emitter, you always have two ways to start/stop an emitter. Both are equally valid and exist to support your personal taste of coding. Either do it all through the global PARTSYS
or do it right on the instance of your emitter, whatever you prefer.
Here are the functions offered by the ParticleEmitter
/// @function set_offset(xoff, yoff)
/// @description sets a static offset distance to apply when following an instance
set_offset = function(xoff, yoff) {
/// @function stream(particles_per_frame = undefined, particle_name = undefined)
/// @description Starts streaming particles as defined for the emitter.
/// If you don't supply any parameters, the values from the variable definitions
/// (which hold the defaults from Particle Editor) are used.
stream = function(particles_per_frame = undefined, particle_name = undefined) {
/// @function stop()
/// @description Stops streaming
stop = function() {
/// @function burst(particle_count = undefined, particle_name = undefined, stop_streaming = true)
/// @description Immediately bursts out n particles
/// If you don't supply any parameters, the values from the variable definitions
/// (which hold the defaults from Particle Editor) are used.
/// If no burst_particle_name is set in the variable definitions, the
/// stream_particle_name is used.
burst = function(particle_count = undefined, particle_name = undefined, stop_streaming = true) {