Since Defold 1.12.2 you can use go.get() and go.set() on individual ParticleFX emitters by passing keys = { "..." }.
This example focuses on this feature. It toggles a ParticleFX between two setups and shows the properties of the active emitters in the labels.
Example consists of one game object in the collection having:
particlefx_set_get.script#particles#label_core and #label_spark

The ParticleFX:
emitter_top and emitter_bottom

The script has the resources exposed as properties:
particles_atlassprites_atlasdefault_materialglow_materialThe current script switches the emitter image directly from code and keeps default_material active for the shown setup.
The example uses 2 atlases with given animations:
particles.atlas with coin and smoke animationssprites.atlas with ship_red and ship_dark animationsThe atlases are set up to contain the animation ids used by the script, so the example can switch between the two setups without extra transition logic. It would also be possible to read the animations from resource.get_atlas(), but this example keeps a small hardcoded ANIMATIONS table to stay as simple as possible.
The script keeps two hardcoded setups and toggles between them whenever you click or tap:
particles.atlas + default particle material
emitter_top uses coin
emitter_bottom uses smokesprites.atlas + default particle material
emitter_top uses ship_red
emitter_bottom uses ship_darkOn startup the script stores the current atlas name, reads back the authored emitter properties, writes them into the labels, and starts the ParticleFX. When the setup changes after that, the script:
{ clear = true }self.atlas_name between sprites_atlas and particles_atlasANIMATIONS tableset_emitter_properties() for each emitter to set image, animation, and materialget_and_print_emitter_properties() to read the current values back with go.get()The helper function set_emitter_properties() applies properties per emitter by passing the emitter id in keys:
go.set("#particles", "image", image, { keys = { "emitter_top" } })
go.set("#particles", "animation", animation, { keys = { "emitter_top" } })
go.set("#particles", "material", material, { keys = { "emitter_top" } })
The helper function get_and_print_emitter_properties() uses the same keys pattern with go.get() and writes the result into the labels, so the example shows which values are currently active for each emitter.
One important limitation: emitter property changes only affect the next play. The script therefore stops the ParticleFX, clears any already spawned particles, applies the new emitter overrides, and then plays it again.
particlefx_set_get.script
-- Properties - 2 atlases:
go.property("particles_atlas", resource.atlas("/assets/particles.atlas"))
go.property("sprites_atlas", resource.atlas("/assets/sprites.atlas"))
-- Properties - 2 materials:
go.property("default_material", resource.material("/builtins/materials/particlefx.material"))
go.property("glow_material", resource.material("/example/particlefx_glow.material"))
-- Predefined table with animations for given atlases:
-- (One can get the animations from resource.get_atlas() too)
local ANIMATIONS = {
["particles_atlas"] = { hash("coin"), hash("smoke") },
["sprites_atlas"] = { hash("ship_red"), hash("ship_dark") }
}
-- Relative address of the particlefx component:
local PARTICLEFX = "#particles"
-- Read the current emitter properties back from the particlefx component
-- and show them in the on-screen labels.
local function get_and_print_emitter_properties(emitter, url)
-- Get the properties of the emitter:
local image = go.get(PARTICLEFX, "image", { keys = { emitter } })
local animation = go.get(PARTICLEFX, "animation", { keys = { emitter } })
local material = go.get(PARTICLEFX, "material", { keys = { emitter } })
-- Show the properties in the label:
label.set_text(url, emitter .. ":\nimage: " .. image
.. "\nanimation: " .. animation .. "\nmaterial: " .. material )
end
-- Apply one full property set to a single emitter.
local function set_emitter_properties(emitter, image, animation, material)
go.set(PARTICLEFX, "image", image, { keys = { emitter } })
go.set(PARTICLEFX, "animation", animation, { keys = { emitter } })
go.set(PARTICLEFX, "material", material, { keys = { emitter } })
end
-- Toggle between the two hardcoded setups:
-- particles atlas + glow material, or sprites atlas + default material.
local function change_particlefx_properties(self)
-- Stop the particlefx before swapping atlas/material overrides.
particlefx.stop(PARTICLEFX, { clear = true })
-- Swap the atlas name and material:
if self.atlas_name == "sprites_atlas" then
self.atlas_name = "particles_atlas"
self.material = self.glow_material
else
self.atlas_name = "sprites_atlas"
self.material = self.default_material
end
-- Get current atlas resource and animations set for it:
local atlas = self[self.atlas_name]
local animations = ANIMATIONS[self.atlas_name]
-- Set the atlas, animation and material for each emitter:
set_emitter_properties("emitter_top", atlas, animations[1], self.material)
set_emitter_properties("emitter_bottom", atlas, animations[2], self.material)
-- Get the current properties and print them in the label for each emitter:
get_and_print_emitter_properties("emitter_top", "#label_core")
get_and_print_emitter_properties("emitter_bottom", "#label_spark")
-- Play the particlefx again:
particlefx.play(PARTICLEFX)
end
function init(self)
-- Acquire input focus to react to the mouse click/touch:
msg.post(".", "acquire_input_focus")
-- Initialize the atlas name:
self.atlas_name = "sprites_atlas"
self.material = self.default_material
-- Get the current properties and print them in the label for each emitter:
get_and_print_emitter_properties("emitter_top", "#label_core")
get_and_print_emitter_properties("emitter_bottom", "#label_spark")
-- Start the ParticleFX:
particlefx.play(PARTICLEFX)
end
function on_input(self, action_id, action)
-- Toggle the setup on touch release:
if action_id == hash("touch") and action.released then
change_particlefx_properties(self)
end
endparticlefx_glow.fp
#version 140
in mediump vec2 var_texcoord0;
in mediump vec4 var_color;
out vec4 out_fragColor;
uniform mediump sampler2D texture_sampler;
uniform fs_uniforms
{
mediump vec4 tint;
};
void main()
{
mediump vec4 tint_pm = vec4(tint.xyz * tint.w, tint.w);
mediump vec4 base = texture(texture_sampler, var_texcoord0.xy) * var_color * tint_pm;
mediump float energy = max(max(base.r, base.g), base.b);
mediump vec3 glow = vec3(0.9, 1.4, 1.8) * energy;
out_fragColor = vec4(base.rgb * 0.2 + glow, base.a);
}