diff --git a/direct/src/particles/ParticleEffect.py b/direct/src/particles/ParticleEffect.py index f801432b7e3..efe61056b64 100644 --- a/direct/src/particles/ParticleEffect.py +++ b/direct/src/particles/ParticleEffect.py @@ -220,10 +220,13 @@ def softStop(self): for particles in self.getParticlesList(): particles.softStop() - def softStart(self): + def softStart(self, firstBirthDelay=None): if self.__isValid(): for particles in self.getParticlesList(): - particles.softStart() + if firstBirthDelay is not None: + particles.softStart(br=-1, first_birth_delay=firstBirthDelay) + else: + particles.softStart() else: # Not asserting here since we want to crash live clients for more expedient bugfix # (Sorry, live clients) diff --git a/panda/src/particlesystem/particleSystem.I b/panda/src/particlesystem/particleSystem.I index a96083f7e22..731ae9d7dcb 100644 --- a/panda/src/particlesystem/particleSystem.I +++ b/panda/src/particlesystem/particleSystem.I @@ -58,6 +58,18 @@ soft_start(PN_stdfloat br) { _tics_since_birth = 0.0f; } +/** + * Causes system to use birth rate set by set_birth_rate(), with the system's + * first birth being delayed by the value of first_birth_delay. Note that a + * negative delay is perfectly valid, causing the first birth to happen + * sooner rather than later. + */ +INLINE void ParticleSystem:: +soft_start(PN_stdfloat br, PN_stdfloat first_birth_delay) { + soft_start(br); + _tics_since_birth = -first_birth_delay; +} + /** * Causes system to use birth rate set by set_soft_birth_rate() */ @@ -342,6 +354,14 @@ get_floor_z() const { return _floor_z; } +/** + +*/ +INLINE PN_stdfloat ParticleSystem:: +get_tics_since_birth() const { + return _tics_since_birth; +} + /** */ diff --git a/panda/src/particlesystem/particleSystem.h b/panda/src/particlesystem/particleSystem.h index 1e5bfdaac8c..23e6f5ce828 100644 --- a/panda/src/particlesystem/particleSystem.h +++ b/panda/src/particlesystem/particleSystem.h @@ -83,6 +83,7 @@ class EXPCL_PANDA_PARTICLESYSTEM ParticleSystem : public Physical { INLINE BaseParticleEmitter *get_emitter() const; INLINE BaseParticleFactory *get_factory() const; INLINE PN_stdfloat get_floor_z() const; + INLINE PN_stdfloat get_tics_since_birth() const; // particle template vector @@ -96,6 +97,7 @@ class EXPCL_PANDA_PARTICLESYSTEM ParticleSystem : public Physical { INLINE void clear_to_initial(); INLINE void soft_stop(PN_stdfloat br = 0.0); INLINE void soft_start(PN_stdfloat br = 0.0); + INLINE void soft_start(PN_stdfloat br, PN_stdfloat first_birth_delay); void update(PN_stdfloat dt); virtual void output(std::ostream &out) const; diff --git a/tests/particles/test_particle_offsetting_and_birth_rate.py b/tests/particles/test_particle_offsetting_and_birth_rate.py new file mode 100644 index 00000000000..6df762816f0 --- /dev/null +++ b/tests/particles/test_particle_offsetting_and_birth_rate.py @@ -0,0 +1,97 @@ +from panda3d.core import NodePath, PandaNode +from direct.particles.ParticleEffect import ParticleEffect +from direct.particles.Particles import Particles + +def test_particle_soft_start(): + # Create a particle effect and a particle system. + # The effect serves to test the Python-level "softStart" + # method, while the systme serves to test the C++-level + # "soft_start" method (via the associated Python "softStart" + # method) + effect = ParticleEffect() + system = Particles("testSystem", 10) + + # Setup some dummy nodes, since it seems to want them + system.setRenderParent(NodePath(PandaNode("test"))) + system.setSpawnRenderNodePath(NodePath(PandaNode("test"))) + + # Add the system to the effect + effect.addParticles(system) + + # Re-assign the system, just to make sure that we have the + # right object. + system = effect.getParticlesList()[0] + + # First, standard "softStart"--i.e. without either changing + # the birth-rate or applying a delay. This should work as it + # used to. + effect.softStart() + + assert system.getBirthRate() == 0.5 + + # Now, check that the pre-existing single-parameter soft-start, + # which alters the birth-rate, still does so. + system.softStart(1) + + assert system.getBirthRate() == 1 + + # Next, birth-delaying. + + # Run a standard soft-start, then check that the birth-timer + # is zero, as used to be the case on running this command. + effect.softStart() + + assert system.getTicsSinceBirth() == 0 + + # Run an delayed soft-start via the system, then check + # that the birth-timer has the assigned value, + # and that the birth-rate is unchanged. + + # (We pass in a birth-rate ("br") of -1 because the related code + # checks for a birth-rate greater than 0, I believe. This allows + # us to change the delay without affecting the birth-rate.) + system.softStart(br=-1, first_birth_delay=-2) + + assert system.getBirthRate() == 1 + assert system.getTicsSinceBirth() == 2 + + # Now, run a delayed soft-start via the effect, and + # again check that the birth-timer has changed as intended, + # and the birth-rate hasn't changed at all. + effect.softStart(firstBirthDelay=0.25) + + assert system.getBirthRate() == 1 + assert system.getTicsSinceBirth() == -0.25 + + # Update the system, advancing it far enough that it should + # have birthed a particle if not for the delay, but not + # so far that it should have birthed a particle >with< + # the delay. Check thus that no particles have been birthed. + system.update(1) + + assert system.getLivingParticles() == 0 + + # Update the system again, this time far enough that with the + # delay it should have birthed just one particle, and + # then check that this is the case. + system.update(1) + + assert system.getLivingParticles() == 1 + + # And finally, check that an unaltered system births as + # expected given a single update: + systemControl = Particles("testSystem; control", 10) + + systemControl.setRenderParent(NodePath(PandaNode("test 2"))) + systemControl.setSpawnRenderNodePath(NodePath(PandaNode("test 2"))) + + assert systemControl.getBirthRate() == 0.5 + assert systemControl.getTicsSinceBirth() == 0 + + assert systemControl.getLivingParticles() == 0 + + systemControl.update(0.6) + + assert systemControl.getLivingParticles() == 1 + + # Done! :D \ No newline at end of file