C ++ Engine

A two semester long class project on a team. Here I have examples of spawning thousands of particles with memory efficient techniques implementing multiple patterns that are editable with JSON parameters and LUA code and are placed with a third party level editor LDTK

Object Pooling

By reusing allocated particle objects, we can quickly spawn hundreds at a time without effecting performance or frame rate

Code Snippet

//Brief: Gets an unused particle from the pool, if not, makes more
//Author: Li
//Returns: Reference to the free particle
Particle& ParticleSystem::GetFreeParticle()
{
	unsigned size = _particles.size();
	if (size > 0 && _activeParticles < size)
	{
		//assign a deactivated particle
		for (unsigned i = 0; i < size; ++i)
		{
			if (!_particles[i].IsActive())
			{
				return _particles[i];
			}
		}
	}
	//create and add a new one
	Particle newParticle = Particle();
	_particles.push_back(newParticle);
	return _particles.back();
}

Pattern Serialization

By reading in serialized parameters from JSON, particle patterns can be edited on the fly without rebuilding. These patterns are loaded into emitter components that respond to triggers from LUA behaviour read in from Behaviour components allowing for the same build level customization from designers

Code Snippet

void ParticleEmitter::Read(jsonObj data)
{
	name = GetParent()->GetName() + GetParent()->GetID();
	_numParticles = data.getInt("NumberOfParticles");
	_maxEmitSpeed = data.getFloat("Speed");
	_maxScale = data.getFloat("Scale") * 32.0f;
	_loopDelay = data.getFloat("Delay");
	_depth = data.getInt("Depth");
	if (_loopDelay > 0)
	{
		_looping = true;
	}
	if (_playOnAwake)
	{
		_wait = true;
	}
	//Read what kind of particle it's emmiting with a string member from deserializer
	if (data.getString("Type") == "Burst")
	{
		int partNum = 0;

		if (data.hasObject("MaxParticle") && data.hasObject("MinParticle"))
		{
			Random r = Random(data.getInt("MinParticle"), data.getInt("MaxParticle"));
			partNum = r.getRandomInt();
		}
		else
		{
			partNum = _numParticles;
		}

		BurstPattern* BurstP = new BurstPattern(partNum);

		if (data.hasObject("MaxSpeed") && data.hasObject("MinSpeed"))
		{
			BurstP->SetSpeeds(data.getFloat("MinSpeed"), data.getFloat("MaxSpeed"));
		}

		if (data.hasObject("MinLifeSpan") && data.hasObject("MaxLifeSpan"))
		{
			BurstP->SetLifeSpan(data.getFloat("MinLifeSpan"), data.getFloat("MaxLifeSpan"));
		}

		if (data.hasObject("MaxScale") && data.hasObject("MinScale"))
		{
			BurstP->SetScale(data.getFloat("MinScale"), data.getFloat("MaxScale"));
		}

		if (data.hasObject("MaxRot") && data.hasObject("MinRot"))
		{
			BurstP->SetRot(data.getFloat("MinRot"), data.getFloat("MaxRot"));
		}

		if (data.hasObject("MaxRotSpeed") && data.hasObject("MinRotSpeed"))
		{
			BurstP->SetRotSpeed(data.getFloat("MinRotSpeed"), data.getFloat("MaxRotSpeed"));
		}

		_pattern = dynamic_cast(IParticlePattern*)(BurstP);

	}
	if (data.getString("Type") == "Trail")
	{
		_pattern = dynamic_cast(IParticlePattern*)(new TrailPattern());
		_active = true;
	}
	_texture = ParticleSystem::instance()->AddTexture(name,data.getString("texturePath"));
}