Defining the Initialization Policy and Action PolicySo how can we go about designing the Policy objects? We could start by building a complete Policy object, which defines policies for color, size, velocity, position, and life. Again, we choose to allow for extensibility and go with templates, thus allowing different policies to be plugged in for different cases. Let's say you decided to do an explosion which requires spherical velocity movement. You simply specify a SphericalVelocityInitializationPolicy as the template parameter for VelocityPolicy, and it can initializes the particle's velocity to move in spherical motion. And what if you wanted to add a gravitational pull? You can simply plug in a GravitationalPolicy as a VelocityPolicy as well, and it gets processed. Color fading? Wind? Your effects are only limited by the number of policies you have at the moment. If you need another effect, you can simply code another one, which can be reused and plugged in for future uses. template <class ParticleType, class ColorPolicy, class SizePolicy, class VelocityPolicy, class LifePolicy, class PositionPolicy> class CompletePolicy { public : PositionPolicy d_PositionPolicy; ColorPolicy d_ColorPolicy; SizePolicy d_SizePolicy; VelocityPolicy d_VelocityPolicy; LifePolicy d_LifePolicy; inline void PrepareAction() throw() { d_PositionPolicy.PrepareAction(); d_VelocityPolicy.PrepareAction(); d_SizePolicy.PrepareAction(); d_ColorPolicy.PrepareAction(); d_LifePolicy.PrepareAction(); } inline void operator()(ParticleType& m_Particle) const throw() { d_PositionPolicy(m_Particle); d_ColorPolicy(m_Particle); d_SizePolicy(m_Particle); d_VelocityPolicy(m_Particle); d_LifePolicy(m_Particle); } }; // end of class CompletePolicy Note that the calls are hinted to be inline, so they can replace those function calls in particle system, thus reducing the possible function call overhead. Individual PolicyIndividual policy will follow the similar design of CompletePolicy, though you can omit the PrepareAction function call for InitializePolicy. Below are three sample policies, one for Life, one for Gravity, and one essential Move, which moves the particle to their new position(as a PositionPolicy). template <class ParticleType> class LifeInitializer { public : int d_nLifeMin; private : int d_nLifeRange; public : // Sets the maximum life range. inline void SetLifeRange(const int& i_nLifeMin, const int& i_nLifeMax) throw() { d_nLifeMin = i_nLifeMin; d_nLifeRange = i_nLifeMax + 1 - d_nLifeMin; } explicit LifeInitializer() throw():d_nLifeMin(0), d_nLifeRange(0) {} inline void operator()(ParticleType& m_Particle) const throw() { m_Particle.d_nLife = d_nLifeMin + rand() % d_nLifeRange; } }; // end of class LifeInitializer template <class ParticleType> class GravityAction { public : Vector3D d_vGravity; public : explicit GravityAction() throw():d_vGravity(0.0f, 0.0f, 0.0f) {} inline void PrepareAction() throw() {} inline void operator()(ParticleType& m_Particle) const throw() { m_Particle.d_vVelocity += d_vGravity; } }; // end of class GravityAction template <class ParticleType> class MoveAction { public : inline void PrepareAction() throw() {} inline void operator()(ParticleType& m_Particle) const throw() { m_Particle.d_ptPos += m_Particle.d_vVelocity; } }; // end of class MoveAction Note, however, the drawback of this template design is that the particle structure you come up with must provide the necessary properties and naming that you use in each of your policies. Also take note of the use of the keyword inline here, which once again hints to the compiler to include those code simply in the callee function. With these inline keywords, the Process function can eliminate any further function calls and execute them there and then! |
|