Using the ParticleFactory

Next, we will need to adjust our previously created Particle archetype and component to reflect these changes.

First, we want to change our .ini file. Since the Particle object is meant for all particle types, instead of having the properties being set there, we will instead set a base type for us to use:

posX   = 0 
posY = 0
velX = 0
velY = 0
scaleX = 2.5
scaleY = 2.5
rot = 0
rotVel = 0
components = GfxComponent ParticleComponent

[GfxComponent]
texture = particle.tga
drawSpace = world

[ParticleComponent]
type = Moving

This simplifies the particle object itself, but it's for a good cause. We will now update the code of the ParticleComponent class as follows:

/******************************************************************************/ 
/*!
Construtor for ParticleSystem component. Sets default values
*/
/******************************************************************************/
ParticleComponent::ParticleComponent() :
M5Component(CT_ParticleComponent)
{
}

/******************************************************************************/
/*!
Takes care of the particle system, decrease lifetime and adjust scaling.
Will mark for destruction if needed.

param [in] dt
The time in seconds since the last frame.
*/
/******************************************************************************/
void ParticleComponent::Update(float dt)
{
// Decrease our life by the change in time this frame (delta time, dt)
lifeLeft -= dt;

ParticleFactory::GetParticleSystem(particleType).Update(m_pObj, dt, lifeLeft);

// If there is no life left, destroy our object
if (lifeLeft <= 0)
{
m_pObj->isDead = true;
}

}

In this instance, you'll notice that instead of modifying the scale and/or movement being done here, we use the ParticleFactory to update our code based on the particleType property:

/******************************************************************************/ 
/*!
Clones the current component and updates it with the correct information.

eturn
A new component that is a clone of this one
*/
/******************************************************************************/
M5Component * ParticleComponent::Clone(void)
{
ParticleComponent * pNew = new ParticleComponent;
pNew->m_pObj = m_pObj;
pNew->particleType = particleType;

ParticleSystem & system =
ParticleFactory::GetParticleSystem(particleType);
system.Init(pNew->m_pObj);
pNew->lifeLeft = system.lifeTime;
return pNew;
}

Here, we call the Init function for our particle system based on its type from the factory:

/******************************************************************************/ 
/*!
Reads in data from a preloaded ini file.

param [in] iniFile
The preloaded inifile to read from.
*/
/******************************************************************************/
void ParticleComponent::FromFile(M5IniFile& iniFile)
{
// Get our initial particle type
std::string particleTypeText;
iniFile.SetToSection("ParticleComponent");
iniFile.GetValue("type", particleTypeText);

if (particleTypeText == "Static")
{
particleType = PS_Static;
}
else if(particleTypeText == "Moving")
{
particleType = PS_Moving;
}

}

We are now going to set our particle type based on what is marked on the ini file.

But, of course, now that we are using the GetParticleSystem function, we need to implement it for our code to compile:

/******************************************************************************/ 
/*!
Used to get our Flyweight object and access the shared properties of the
particles.

param type
What kind of particle we want to get access to

*/
/******************************************************************************/
ParticleSystem & ParticleFactory::GetParticleSystem(ParticleType type)
{
// If our object exists, return it
if (particleSystems.find(type) != particleSystems.end())
{
return *particleSystems[type];
}

ParticleSystem * newSystem = nullptr;

// Otherwise, let's create one
switch (type)
{
case PS_Static:
newSystem = new StaticParticleSystem();
newSystem->endScale = 0;
newSystem->lifeTime = 1.5;
newSystem->startScale = M5Vec2(2.5, 2.5);

particleSystems[PS_Static] = newSystem;

objectCount++;
break;

case PS_Moving:
newSystem = new MovingParticleSystem();
newSystem->endScale = 0;
newSystem->lifeTime = 1.5;
newSystem->startScale = M5Vec2(2.5, 2.5);
particleSystems[PS_Moving] = newSystem;
objectCount++;
break;
}

return *newSystem;

}

In this script, we make use of the particleSystems map that we talked about earlier. The first thing that we do is check if there is an object in the map that has our ParticleType in it. If not, then we need to create one. In this case, I added a switch statement that will assign different values depending on the value mentioned in the case statement, but you could easily read these values from a text file in a similar manner to how files are read for archetypes. You'll notice that we are calling new in order to create these, so we will need to call delete on them as well in order to avoid any memory leaks. To accomplish this, I've added in a destructor for the ParticleFactory class:

/******************************************************************************/ 
/*!
Deconstructor for the ParticleFactory. Removes all of the elements in ourparticleSystems map

*/
/******************************************************************************/
ParticleFactory::~ParticleFactory()
{
for (auto iterator = particleSystems.begin();
iterator != particleSystems.end();
iterator++)
{
// iterator->first = key
// iterator->second = value
delete iterator->second;
}

}

Finally, we need to write the implementations for our different ParticleSystems:

/******************************************************************************/ 
/*!
Will give you the percentage of the fraction from start to end

param start
What value to start from

param end
What value to end from

param fraction
What percentage of the way we are from start to finish

*/
/******************************************************************************/
float ParticleSystem::Lerp(float start, float end, float fraction)
{
return start + fraction * (end - start);
}

The Lerp function does the same for either particle type, so it's fine the way it was:

/******************************************************************************/ 
/*!
Used to initialize the particle system and set any parameters needed

param obj
A reference to the object

*/
/******************************************************************************/
void StaticParticleSystem::Init(M5Object * obj)
{
obj->vel = M5Vec2(0, 0);
}

/******************************************************************************/
/*!
Used to update the particle system. Called once per frame

param m_pObj
A reference to the object

param dt
Amount of time that has passed since the previous frame

param lifeLeft
The amount of lifetime the object has left

*/
/******************************************************************************/
void StaticParticleSystem::Update(M5Object * m_pObj,
float /*dt*/, float lifeLeft)
{
// Change our size based on where we want it to be
float currentPercentage = 1 - (lifeLeft / lifeTime);
m_pObj->scale.x = Lerp(startScale.x,
startScale.x * endScale, currentPercentage);
m_pObj->scale.y = Lerp(startScale.y,
startScale.y * endScale, currentPercentage);
}

The static version of the Init and Update functions will just set our velocity to 0 so we don't move:

/******************************************************************************/ 
/*!
Used to initialize the particle system and set any parameters needed

param obj
A reference to the object

*/
/******************************************************************************/
void MovingParticleSystem::Init(M5Object * obj)
{
obj->vel = M5Vec2(M5Random::GetFloat(-1, 1),
M5Random::GetFloat(-1, 1)) * 10;
}

/******************************************************************************/
/*!
Used to update the particle system. Called once per frame

param m_pObj
A reference to the object

param dt
Amount of time that has passed since the previous frame

param lifeLeft
The amount of lifetime the object has left

*/
/******************************************************************************/
void MovingParticleSystem::Update(M5Object * m_pObj, float /*dt*/, float lifeLeft)
{
// Change our size based on where we want it to be
float currentPercentage = 1 - (lifeLeft / lifeTime);
m_pObj->scale.x = Lerp(startScale.x,
startScale.x * endScale, currentPercentage);
m_pObj->scale.y = Lerp(startScale.y,
startScale.y * endScale, currentPercentage);
}

For our moving particle system, we will set our velocity to a random number in the x and y axis, causing a nice explosion effect!

Now, instead of creating a copy of this data each time, we will have one copy that we will access, as shown in the following screenshot:

As we play, you'll notice that we now have a new particle system working and it's doing its job quite well.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.45.5