Skip to content

Instantly share code, notes, and snippets.

@DarkRoku12
Created July 19, 2021 19:40
Show Gist options
  • Save DarkRoku12/8da49e446e2b4206126c95a87da9d38e to your computer and use it in GitHub Desktop.
Save DarkRoku12/8da49e446e2b4206126c95a87da9d38e to your computer and use it in GitHub Desktop.
Base particle system for 2D game engine
#include <algorithm>
#include "ps_system.hpp"
#include "ps_particle.hpp"
#include "ps_emitters.hpp"
// Effects - Multi-thread:
void ParticleSystem::applyEffectsMultiThread( int id , updater_data ud )
{
std::vector< Particle > *particles = ud.particles;
sf::VertexArray *vertices = ud.vertices;
float deltaTime = ud.DT;
auto effects = ud.effects;
vertices->clear();
auto deadCount = particles->begin();
for(auto p = particles->begin(); p != particles->end(); ++p) // p = particle.
{
p->lifeSpan += deltaTime;
if(p->lifeSpan < p->lifeSpanMax)
{
p->position += deltaTime * p->velocity;
p->rotation += deltaTime * p->rotationSpeed;
p->scale += deltaTime * p->grow;
for(auto &e : *effects)
{
e->modifier( *p , deltaTime );
}
sf::Transform transform;
transform.translate( p->position );
transform.rotate( p->rotation );
transform.scale( p->scale );
std::array< sf::Vertex , 4 > verts;
for(int i = 0; i < 4; ++i)
{
sf::Vertex *v = &verts[i];
v->position = transform.transformPoint( p->mask.position[i] );
v->texCoords = p->mask.texCoords[i];
v->color = p->color;
}
vertices->append( verts[0] ); vertices->append( verts[1] ); vertices->append( verts[2] ); // ABC triangle.
vertices->append( verts[0] ); vertices->append( verts[3] ); vertices->append( verts[2] ); // ADC triangle.
*deadCount++ = *p;
}
}
particles->erase( deadCount , particles->end() );
}
// System:
void ParticleSystem::System::update( float DT )
{
this->deltaTime = DT;
for(auto &emitter : emitters)
{
emitter->emit( *this , DT );
}
if(this->MT_IS_ENABLED)
{
udA.DT = DT; udB.DT = DT;
auto A = pool.push( applyEffectsMultiThread , udA ); auto B = pool.push( applyEffectsMultiThread , udB );
A.wait(); B.wait();
}
else
{
applyEffects( &particlesA , &verticesA );
}
}
bool ParticleSystem::System::switchMultiThread()
{
MT_IS_ENABLED = !MT_IS_ENABLED;
clear();
if(MT_IS_ENABLED){ pool.resize( std::max( 1u , std::thread::hardware_concurrency() ) ); }
else { pool.resize( 0 ); }
return MT_IS_ENABLED;
}
void ParticleSystem::System::draw( sf::RenderTarget &target , sf::RenderStates states ) const
{
states.texture = texture;
target.draw( verticesA , states );
target.draw( verticesB , states );
}
void ParticleSystem::System::applyEffects( std::vector< Particle > *particles , sf::VertexArray *vertices )
{
vertices->clear();
auto deadCount = particles->begin();
for(auto p = particles->begin(); p != particles->end(); ++p) // p = particle.
{
p->lifeSpan += deltaTime;
if(p->lifeSpan < p->lifeSpanMax)
{
p->position += deltaTime * p->velocity;
p->rotation += deltaTime * p->rotationSpeed;
p->scale += deltaTime * p->grow;
for(auto &e : effects)
{
e->modifier( *p , deltaTime );
}
sf::Transform transform;
transform.translate( p->position );
transform.rotate( p->rotation );
transform.scale( p->scale );
std::array< sf::Vertex , 4 > verts;
for(int i = 0; i < 4; ++i)
{
sf::Vertex *v = &verts[i];
v->position = transform.transformPoint( p->mask.position[i] );
v->texCoords = p->mask.texCoords[i];
v->color = p->color;
}
vertices->append( verts[0] ); vertices->append( verts[1] ); vertices->append( verts[2] ); // ABC triangle.
vertices->append( verts[0] ); vertices->append( verts[3] ); vertices->append( verts[2] ); // ADC triangle.
*deadCount++ = *p;
}
}
particles->erase( deadCount , particles->end() );
}
void ParticleSystem::System::removeEmitter( Emitter *e )
{
emitters.erase( std::remove( emitters.begin() , emitters.end() , e ) , emitters.end() );
}
void ParticleSystem::System::addEmitter( Emitter *e )
{
emitters.push_back( e );
}
void ParticleSystem::System::removeEffect( Effects::Effects *e )
{
effects.erase( std::remove( effects.begin() , effects.end() , e ) , effects.end() );
}
void ParticleSystem::System::addEffect( Effects::Effects *e )
{
effects.push_back( e );
}
int ParticleSystem::System::getParticleCount() const
{
return particlesA.size() + particlesB.size();
}
void ParticleSystem::System::clear()
{
particlesA.clear(); particlesB.clear(); verticesA.clear(); verticesB.clear();
}
void ParticleSystem::System::newParticleB( const Particle &p )
{
particlesB.push_back( p );
}
void ParticleSystem::System::newParticleA( const Particle &p )
{
particlesA.push_back( p );
}
void ParticleSystem::System::newParticle( const Particle &p , int amount )
{
if(particlesA.size() > amount)
{
return ;
}
particlesA.push_back( p );
}
void ParticleSystem::System::newParticle( const Particle &p )
{
if(MT_IS_ENABLED && particlesB.size() < particlesA.size())
{
particlesB.push_back( p );
}
else
{
particlesA.push_back( p );
}
}
ParticleSystem::System::System( sf::Texture &t , Mask _mask ) : deltaTime( 0 )
{
MT_IS_ENABLED = false ; // Multi-threading, disable by default.
texture = &t ;
masks.push_back( _mask );
verticesA.setPrimitiveType( sf::Triangles ); verticesB.setPrimitiveType( sf::Triangles );
verticesA.resize( 5000 ); verticesB.resize( 5000 );
verticesA.clear(); verticesB.clear();
particlesA.reserve( 1100 ); particlesB.reserve( 1100 );
udA.effects = &effects; udB.effects = &effects;
udA.particles = &particlesA; udA.vertices = &verticesA;
udB.particles = &particlesB; udB.vertices = &verticesB;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment