|
31 | 31 | #include "gpu_particles_3d.h" |
32 | 32 |
|
33 | 33 | #include "scene/resources/particle_process_material.h" |
| 34 | +#include "scene/scene_string_names.h" |
34 | 35 |
|
35 | 36 | AABB GPUParticles3D::get_aabb() const { |
36 | 37 | return AABB(); |
37 | 38 | } |
38 | 39 |
|
39 | 40 | void GPUParticles3D::set_emitting(bool p_emitting) { |
40 | | - RS::get_singleton()->particles_set_emitting(particles, p_emitting); |
| 41 | + // Do not return even if `p_emitting == emitting` because `emitting` is just an approximation. |
41 | 42 |
|
42 | 43 | if (p_emitting && one_shot) { |
| 44 | + if (!active && !emitting) { |
| 45 | + // Last cycle ended. |
| 46 | + active = true; |
| 47 | + time = 0; |
| 48 | + signal_cancled = false; |
| 49 | + emission_time = lifetime; |
| 50 | + active_time = lifetime * (2 - explosiveness_ratio); |
| 51 | + } else { |
| 52 | + signal_cancled = true; |
| 53 | + } |
43 | 54 | set_process_internal(true); |
44 | 55 | } else if (!p_emitting) { |
45 | | - set_process_internal(false); |
| 56 | + if (one_shot) { |
| 57 | + set_process_internal(true); |
| 58 | + } else { |
| 59 | + set_process_internal(false); |
| 60 | + } |
46 | 61 | } |
| 62 | + |
| 63 | + emitting = p_emitting; |
| 64 | + RS::get_singleton()->particles_set_emitting(particles, p_emitting); |
47 | 65 | } |
48 | 66 |
|
49 | 67 | void GPUParticles3D::set_amount(int p_amount) { |
@@ -122,7 +140,7 @@ void GPUParticles3D::set_collision_base_size(real_t p_size) { |
122 | 140 | } |
123 | 141 |
|
124 | 142 | bool GPUParticles3D::is_emitting() const { |
125 | | - return RS::get_singleton()->particles_get_emitting(particles); |
| 143 | + return emitting; |
126 | 144 | } |
127 | 145 |
|
128 | 146 | int GPUParticles3D::get_amount() const { |
@@ -373,6 +391,16 @@ PackedStringArray GPUParticles3D::get_configuration_warnings() const { |
373 | 391 | void GPUParticles3D::restart() { |
374 | 392 | RenderingServer::get_singleton()->particles_restart(particles); |
375 | 393 | RenderingServer::get_singleton()->particles_set_emitting(particles, true); |
| 394 | + |
| 395 | + emitting = true; |
| 396 | + active = true; |
| 397 | + signal_cancled = false; |
| 398 | + time = 0; |
| 399 | + emission_time = lifetime * (1 - explosiveness_ratio); |
| 400 | + active_time = lifetime * (2 - explosiveness_ratio); |
| 401 | + if (one_shot) { |
| 402 | + set_process_internal(true); |
| 403 | + } |
376 | 404 | } |
377 | 405 |
|
378 | 406 | AABB GPUParticles3D::capture_aabb() const { |
@@ -425,9 +453,23 @@ void GPUParticles3D::_notification(int p_what) { |
425 | 453 | // Use internal process when emitting and one_shot is on so that when |
426 | 454 | // the shot ends the editor can properly update. |
427 | 455 | case NOTIFICATION_INTERNAL_PROCESS: { |
428 | | - if (one_shot && !is_emitting()) { |
429 | | - notify_property_list_changed(); |
430 | | - set_process_internal(false); |
| 456 | + if (one_shot) { |
| 457 | + time += get_process_delta_time(); |
| 458 | + if (time > emission_time) { |
| 459 | + emitting = false; |
| 460 | + if (!active) { |
| 461 | + set_process_internal(false); |
| 462 | + } |
| 463 | + } |
| 464 | + if (time > active_time) { |
| 465 | + if (active && !signal_cancled) { |
| 466 | + emit_signal(SceneStringNames::get_singleton()->finished); |
| 467 | + } |
| 468 | + active = false; |
| 469 | + if (!emitting) { |
| 470 | + set_process_internal(false); |
| 471 | + } |
| 472 | + } |
431 | 473 | } |
432 | 474 | } break; |
433 | 475 |
|
@@ -571,6 +613,8 @@ void GPUParticles3D::_bind_methods() { |
571 | 613 | ClassDB::bind_method(D_METHOD("set_transform_align", "align"), &GPUParticles3D::set_transform_align); |
572 | 614 | ClassDB::bind_method(D_METHOD("get_transform_align"), &GPUParticles3D::get_transform_align); |
573 | 615 |
|
| 616 | + ADD_SIGNAL(MethodInfo("finished")); |
| 617 | + |
574 | 618 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); |
575 | 619 | ADD_PROPERTY_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false. |
576 | 620 | ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); |
|
0 commit comments