diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml index 314e46d9d018..445f9d06615a 100644 --- a/doc/classes/CPUParticles2D.xml +++ b/doc/classes/CPUParticles2D.xml @@ -89,6 +89,11 @@ Number of particles emitted in one emission cycle. + + Amount Ratio multiplied by [member amount] is how many particles will be emmitted each cycle. This value is to be adjusted while emitting particles as it will not clear the existing particles. + When not used leave this ratio at 1 and adjust amount accordingly. + Setting this value to zero will clear [member emitting] flag, increasing it from zero will set emitting. + Each particle's rotation will be animated along this [Curve]. diff --git a/doc/classes/CPUParticles3D.xml b/doc/classes/CPUParticles3D.xml index 3a15a117f5f1..9a8cf62b2a24 100644 --- a/doc/classes/CPUParticles3D.xml +++ b/doc/classes/CPUParticles3D.xml @@ -88,6 +88,11 @@ Number of particles emitted in one emission cycle. + + Amount Ratio multiplied by [member amount] is how many particles will be emmitted each cycle. This value is to be adjusted while emitting particles as it will not clear the existing particles. + When not used leave this ratio at 1 and adjust amount accordingly. + Setting this value to zero will clear [member emitting] flag, increasing it from zero will set emitting. + Each particle's rotation will be animated along this [Curve]. diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index c6296f4732e4..8e5f1ac52f4a 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -61,6 +61,32 @@ void CPUParticles2D::set_amount(int p_amount) { RS::get_singleton()->multimesh_allocate_data(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_2D, true, true); particle_order.resize(p_amount); + set_amount_ratio(amount_ratio); +} + +void CPUParticles2D::set_amount_ratio(float p_amount_ratio) { + if (p_amount_ratio == 0) { + set_emitting(false); + } else if (!emitting && amount_ratio == 0) { + set_emitting(true); + } + + amount_ratio = p_amount_ratio; + + float tot = 1; + int pcount = particles.size(); + Particle *w = particles.ptrw(); + + for (int i = 0; i < pcount; i++) { + tot += amount_ratio; + w[i].stopped = false; + if (tot >= 1) { + w[i].stopping = false; + tot -= 1; + } else { + w[i].stopping = true; + } + } } void CPUParticles2D::set_lifetime(double p_lifetime) { @@ -105,6 +131,10 @@ int CPUParticles2D::get_amount() const { return particles.size(); } +float CPUParticles2D::get_amount_ratio() const { + return amount_ratio; +} + double CPUParticles2D::get_lifetime() const { return lifetime; } @@ -653,6 +683,10 @@ void CPUParticles2D::_particles_process(double p_delta) { for (int i = 0; i < pcount; i++) { Particle &p = parray[i]; + if (p.stopped) { + continue; + } + if (!emitting && !p.active) { continue; } @@ -711,6 +745,12 @@ void CPUParticles2D::_particles_process(double p_delta) { float tv = 0.0; if (restart) { + if (p.stopping) { + p.stopped = true; + p.active = false; + continue; + } + if (!emitting) { p.active = false; continue; @@ -1249,6 +1289,7 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) { void CPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &CPUParticles2D::set_emitting); ClassDB::bind_method(D_METHOD("set_amount", "amount"), &CPUParticles2D::set_amount); + ClassDB::bind_method(D_METHOD("set_amount_ratio", "amount_ratio"), &CPUParticles2D::set_amount_ratio); ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &CPUParticles2D::set_lifetime); ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &CPUParticles2D::set_one_shot); ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &CPUParticles2D::set_pre_process_time); @@ -1262,6 +1303,7 @@ void CPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_emitting"), &CPUParticles2D::is_emitting); ClassDB::bind_method(D_METHOD("get_amount"), &CPUParticles2D::get_amount); + ClassDB::bind_method(D_METHOD("get_amount_ratio"), &CPUParticles2D::get_amount_ratio); ClassDB::bind_method(D_METHOD("get_lifetime"), &CPUParticles2D::get_lifetime); ClassDB::bind_method(D_METHOD("get_one_shot"), &CPUParticles2D::get_one_shot); ClassDB::bind_method(D_METHOD("get_pre_process_time"), &CPUParticles2D::get_pre_process_time); @@ -1284,6 +1326,7 @@ void CPUParticles2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amount_ratio", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_amount_ratio", "get_amount_ratio"); ADD_GROUP("Time", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,suffix:s"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); @@ -1469,6 +1512,7 @@ CPUParticles2D::CPUParticles2D() { set_emitting(true); set_amount(8); + set_amount_ratio(1); set_use_local_coordinates(false); set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0); diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index 141e5f913942..9d8749b48d9c 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -86,6 +86,8 @@ class CPUParticles2D : public Node2D { real_t rotation = 0.0; Vector2 velocity; bool active = false; + bool stopping = false; + bool stopped = false; real_t angle_rand = 0.0; real_t scale_rand = 0.0; real_t hue_rot_rand = 0.0; @@ -131,6 +133,7 @@ class CPUParticles2D : public Node2D { bool one_shot = false; + float amount_ratio = 1; double lifetime = 1.0; double pre_process_time = 0.0; real_t explosiveness_ratio = 0.0; @@ -198,6 +201,7 @@ class CPUParticles2D : public Node2D { public: void set_emitting(bool p_emitting); void set_amount(int p_amount); + void set_amount_ratio(float p_amount_ratio); void set_lifetime(double p_lifetime); void set_one_shot(bool p_one_shot); void set_pre_process_time(double p_time); @@ -209,6 +213,7 @@ class CPUParticles2D : public Node2D { bool is_emitting() const; int get_amount() const; + float get_amount_ratio() const; double get_lifetime() const; bool get_one_shot() const; double get_pre_process_time() const; diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index 5ac8535bb62f..b74a6d3a1d77 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -73,6 +73,32 @@ void CPUParticles3D::set_amount(int p_amount) { RS::get_singleton()->multimesh_allocate_data(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_3D, true, true); particle_order.resize(p_amount); + set_amount_ratio(amount_ratio); +} + +void CPUParticles3D::set_amount_ratio(float p_amount_ratio) { + if (p_amount_ratio == 0) { + set_emitting(false); + } else if (!emitting && amount_ratio == 0) { + set_emitting(true); + } + + amount_ratio = p_amount_ratio; + + float tot = 1; + int pcount = particles.size(); + Particle *w = particles.ptrw(); + + for (int i = 0; i < pcount; i++) { + tot += amount_ratio; + w[i].stopped = false; + if (tot >= 1) { + w[i].stopping = false; + tot -= 1; + } else { + w[i].stopping = true; + } + } } void CPUParticles3D::set_lifetime(double p_lifetime) { @@ -116,6 +142,10 @@ int CPUParticles3D::get_amount() const { return particles.size(); } +float CPUParticles3D::get_amount_ratio() const { + return amount_ratio; +} + double CPUParticles3D::get_lifetime() const { return lifetime; } @@ -673,6 +703,10 @@ void CPUParticles3D::_particles_process(double p_delta) { for (int i = 0; i < pcount; i++) { Particle &p = parray[i]; + if (p.stopped) { + continue; + } + if (!emitting && !p.active) { continue; } @@ -731,6 +765,12 @@ void CPUParticles3D::_particles_process(double p_delta) { float tv = 0.0; if (restart) { + if (p.stopping) { + p.stopped = true; + p.active = false; + continue; + } + if (!emitting) { p.active = false; continue; @@ -1410,6 +1450,7 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) { void CPUParticles3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &CPUParticles3D::set_emitting); ClassDB::bind_method(D_METHOD("set_amount", "amount"), &CPUParticles3D::set_amount); + ClassDB::bind_method(D_METHOD("set_amount_ratio", "amount_ratio"), &CPUParticles3D::set_amount_ratio); ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &CPUParticles3D::set_lifetime); ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &CPUParticles3D::set_one_shot); ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &CPUParticles3D::set_pre_process_time); @@ -1423,6 +1464,7 @@ void CPUParticles3D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_emitting"), &CPUParticles3D::is_emitting); ClassDB::bind_method(D_METHOD("get_amount"), &CPUParticles3D::get_amount); + ClassDB::bind_method(D_METHOD("get_amount_ratio"), &CPUParticles3D::get_amount_ratio); ClassDB::bind_method(D_METHOD("get_lifetime"), &CPUParticles3D::get_lifetime); ClassDB::bind_method(D_METHOD("get_one_shot"), &CPUParticles3D::get_one_shot); ClassDB::bind_method(D_METHOD("get_pre_process_time"), &CPUParticles3D::get_pre_process_time); @@ -1445,6 +1487,7 @@ void CPUParticles3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amount_ratio", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_amount_ratio", "get_amount_ratio"); ADD_GROUP("Time", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,exp,suffix:s"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); @@ -1658,6 +1701,7 @@ CPUParticles3D::CPUParticles3D() { set_emitting(true); set_amount(8); + set_amount_ratio(1); set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0); set_param_min(PARAM_ANGULAR_VELOCITY, 0); diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h index 6b7013773664..0990a5d8d350 100644 --- a/scene/3d/cpu_particles_3d.h +++ b/scene/3d/cpu_particles_3d.h @@ -88,6 +88,8 @@ class CPUParticles3D : public GeometryInstance3D { real_t custom[4] = {}; Vector3 velocity; bool active = false; + bool stopping = false; + bool stopped = false; real_t angle_rand = 0.0; real_t scale_rand = 0.0; real_t hue_rot_rand = 0.0; @@ -132,6 +134,7 @@ class CPUParticles3D : public GeometryInstance3D { bool one_shot = false; + float amount_ratio = 1; double lifetime = 1.0; double pre_process_time = 0.0; real_t explosiveness_ratio = 0.0; @@ -205,6 +208,7 @@ class CPUParticles3D : public GeometryInstance3D { void set_emitting(bool p_emitting); void set_amount(int p_amount); + void set_amount_ratio(float p_amount_ratio); void set_lifetime(double p_lifetime); void set_one_shot(bool p_one_shot); void set_pre_process_time(double p_time); @@ -216,6 +220,7 @@ class CPUParticles3D : public GeometryInstance3D { bool is_emitting() const; int get_amount() const; + float get_amount_ratio() const; double get_lifetime() const; bool get_one_shot() const; double get_pre_process_time() const;