diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml index 74523ee3977..09f810cb772 100644 --- a/doc/classes/CPUParticles2D.xml +++ b/doc/classes/CPUParticles2D.xml @@ -285,6 +285,13 @@ Particle texture. If [code]null[/code], particles will be squares. + + + + Emitted when all active particles have finished processing. When [member one_shot] is disabled, particles will process continuously, so this is never emitted. + + + Particles are drawn in the order emitted. diff --git a/doc/classes/CPUParticles3D.xml b/doc/classes/CPUParticles3D.xml index 1714ebec716..905f5475be9 100644 --- a/doc/classes/CPUParticles3D.xml +++ b/doc/classes/CPUParticles3D.xml @@ -309,6 +309,13 @@ Minimum tangent acceleration. + + + + Emitted when all active particles have finished processing. When [member one_shot] is disabled, particles will process continuously, so this is never emitted. + + + Particles are drawn in the order emitted. diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 115104adff8..f7d8a10d2d8 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -33,6 +33,7 @@ #include "core/core_string_names.h" #include "scene/2d/gpu_particles_2d.h" #include "scene/resources/particle_process_material.h" +#include "scene/scene_string_names.h" void CPUParticles2D::set_emitting(bool p_emitting) { if (emitting == p_emitting) { @@ -41,6 +42,7 @@ void CPUParticles2D::set_emitting(bool p_emitting) { emitting = p_emitting; if (emitting) { + active = true; set_process_internal(true); } } @@ -259,7 +261,6 @@ PackedStringArray CPUParticles2D::get_configuration_warnings() const { void CPUParticles2D::restart() { time = 0; - inactive_time = 0; frame_remainder = 0; cycle = 0; emitting = false; @@ -561,21 +562,15 @@ void CPUParticles2D::_update_internal() { } double delta = get_process_delta_time(); - if (emitting) { - inactive_time = 0; - } else { - inactive_time += delta; - if (inactive_time > lifetime * 1.2) { - set_process_internal(false); - _set_do_redraw(false); + if (!active && !emitting) { + set_process_internal(false); + _set_do_redraw(false); - //reset variables - time = 0; - inactive_time = 0; - frame_remainder = 0; - cycle = 0; - return; - } + //reset variables + time = 0; + frame_remainder = 0; + cycle = 0; + return; } _set_do_redraw(true); @@ -650,6 +645,7 @@ void CPUParticles2D::_particles_process(double p_delta) { double system_phase = time / lifetime; + bool should_be_active = false; for (int i = 0; i < pcount; i++) { Particle &p = parray[i]; @@ -994,6 +990,12 @@ void CPUParticles2D::_particles_process(double p_delta) { p.transform.columns[1] *= base_scale.y; p.transform[2] += p.velocity * local_delta; + + should_be_active = true; + } + if (!Math::is_equal_approx(time, 0.0) && active && !should_be_active) { + active = false; + emit_signal(SceneStringNames::get_singleton()->finished); } } @@ -1364,6 +1366,8 @@ void CPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles2D::convert_from_particles); + ADD_SIGNAL(MethodInfo("finished")); + ADD_GROUP("Emission Shape", "emission_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Sphere Surface,Rectangle,Points,Directed Points", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01,suffix:px"), "set_emission_sphere_radius", "get_emission_sphere_radius"); diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index d4ff9994594..3f858c32776 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -78,6 +78,7 @@ public: private: bool emitting = false; + bool active = false; struct Particle { Transform2D transform; @@ -99,7 +100,6 @@ private: }; double time = 0.0; - double inactive_time = 0.0; double frame_remainder = 0.0; int cycle = 0; bool do_redraw = false; diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index 405d478a475..4a17919ba58 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -34,6 +34,7 @@ #include "scene/3d/gpu_particles_3d.h" #include "scene/main/viewport.h" #include "scene/resources/particle_process_material.h" +#include "scene/scene_string_names.h" AABB CPUParticles3D::get_aabb() const { return AABB(); @@ -46,6 +47,7 @@ void CPUParticles3D::set_emitting(bool p_emitting) { emitting = p_emitting; if (emitting) { + active = true; set_process_internal(true); // first update before rendering to avoid one frame delay after emitting starts @@ -220,7 +222,6 @@ PackedStringArray CPUParticles3D::get_configuration_warnings() const { void CPUParticles3D::restart() { time = 0; - inactive_time = 0; frame_remainder = 0; cycle = 0; emitting = false; @@ -575,21 +576,15 @@ void CPUParticles3D::_update_internal() { } double delta = get_process_delta_time(); - if (emitting) { - inactive_time = 0; - } else { - inactive_time += delta; - if (inactive_time > lifetime * 1.2) { - set_process_internal(false); - _set_redraw(false); + if (!active && !emitting) { + set_process_internal(false); + _set_redraw(false); - //reset variables - time = 0; - inactive_time = 0; - frame_remainder = 0; - cycle = 0; - return; - } + //reset variables + time = 0; + frame_remainder = 0; + cycle = 0; + return; } _set_redraw(true); @@ -670,6 +665,7 @@ void CPUParticles3D::_particles_process(double p_delta) { double system_phase = time / lifetime; + bool should_be_active = false; for (int i = 0; i < pcount; i++) { Particle &p = parray[i]; @@ -1136,6 +1132,12 @@ void CPUParticles3D::_particles_process(double p_delta) { } p.transform.origin += p.velocity * local_delta; + + should_be_active = true; + } + if (!Math::is_equal_approx(time, 0.0) && active && !should_be_active) { + active = false; + emit_signal(SceneStringNames::get_singleton()->finished); } } @@ -1543,6 +1545,8 @@ void CPUParticles3D::_bind_methods() { ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles3D::convert_from_particles); + ADD_SIGNAL(MethodInfo("finished")); + ADD_GROUP("Emission Shape", "emission_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Sphere Surface,Box,Points,Directed Points,Ring", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius"); diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h index 40ea4e8cdfb..a5bc7dddb9b 100644 --- a/scene/3d/cpu_particles_3d.h +++ b/scene/3d/cpu_particles_3d.h @@ -81,6 +81,7 @@ public: private: bool emitting = false; + bool active = false; struct Particle { Transform3D transform; @@ -101,7 +102,6 @@ private: }; double time = 0.0; - double inactive_time = 0.0; double frame_remainder = 0.0; int cycle = 0; bool redraw = false; diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index 536ffd1fe48..e2eed3ccd37 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -57,7 +57,6 @@ SceneStringNames::SceneStringNames() { sleeping_state_changed = StaticCString::create("sleeping_state_changed"); finished = StaticCString::create("finished"); - emission_finished = StaticCString::create("emission_finished"); animation_finished = StaticCString::create("animation_finished"); animation_changed = StaticCString::create("animation_changed"); animation_started = StaticCString::create("animation_started"); diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index ca8f7a1e7df..41ba26575d9 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -93,7 +93,6 @@ public: StringName sort_children; StringName finished; - StringName emission_finished; StringName animation_finished; StringName animation_changed; StringName animation_started;