Sign in to follow this  
c4c0d3m0n

Please review my simple particle system

Recommended Posts

c4c0d3m0n    100
I created a simple particle system in C++ using classes. It is a 2D system. It works for now. I plan on adding extra options to the system, that's why certain variables are not really used yet. Thanks in forward. psystem.h
#include "particle.h"


class ParticleSystem
{
private:

    std::vector<Particle> system;

    double gravfactor;

    // The box limits in which the Particles may live
    int xleft;
    int xright;
    int ytop;
    int ybottom;
    // A margin in case the particles are represented by something bigger than a pixel
    int margin;

public:

    ParticleSystem( int xleft, int xright, int ytop, int ybottom, int margin, double gravfactor );


    void AddPtc( int x, int y, double velocity, double angle );
    void CreateExplosion( int size, int x, int y, double minvel, double maxvel );

    void UpdateAll( int deltatime );
    void ChangeGrav( double newgravfactor );

    int Size();
    int GetX( int i );
    int GetY( int i );

};




ParticleSystem::ParticleSystem( int xleft, int xright, int ytop, int ybottom, int margin, double gravfactor )
: gravfactor(gravfactor),
  xleft(xleft),
  xright(xright),
  ytop(ytop),
  ybottom(ybottom),
  margin(margin)
{
}


void ParticleSystem::AddPtc( int x, int y, double velocity, double angle )
{
    system.push_back( Particle( x, y, velocity, angle, system.size() ) );
}

void ParticleSystem::CreateExplosion( int size, int x, int y, double minvel, double maxvel )
{
    for( int i = 0; i < size; i++ ) {
        system.push_back( Particle( x, y,
                                    (double)(rand() %(int)((maxvel-minvel) * 100)) / 100.0 + minvel, // minvel to maxvel (.00)
                                    (double)(rand() %360),
                                    system.size() ) );
    }
}


void ParticleSystem::UpdateAll( int deltatime )
{
    for( unsigned int i = 0; i < system.size(); i++ ) {
        system[i].Update( deltatime, gravfactor );
    }

    std::vector<Particle>::iterator iter;

    for( iter = system.begin(); iter != system.end(); iter++ ) {
        if( iter->GetX() + margin < xleft ) {
            system.erase( iter );
            iter--;
        }
        else if( iter->GetX() - margin > xright ) {
            system.erase( iter );
            iter--;
        }
        else if( ( iter->GetY() + margin < ytop ) && ( gravfactor <= 0 ) ) {
            system.erase( iter );
            iter--;
        }
        else if( ( iter->GetY() - margin > ybottom ) && ( gravfactor >= 0 ) ) {
            system.erase( iter );
            iter--;
        }
    }
}

void ParticleSystem::ChangeGrav( double newgravfactor )
{
    gravfactor = newgravfactor;
}


int ParticleSystem::Size()
{
    return system.size();
}

int ParticleSystem::GetX( int i )
{
    return xleft + system[i].GetX();
}

int ParticleSystem::GetY( int i )
{
    return ytop + system[i].GetY();
}




particle.h
class Particle
{
private:

    int ID;
    // Coordinates
    double posx;
    double posy;
    // Velocity in px/ms
    double velx;
    double vely;
    // Lifespan in ms
    int age;
    // Gravitational stuff
    double GRAVITY;

    // Functions
    double toRad( double angdeg ) { return angdeg / 180.0 * 3.14; }

public:

    Particle();
    Particle( int x, int y, double velocity, double angle, int id );


    void Update( int deltatime, double gravfactor );

    int GetX() { return (int)posx; }
    int GetY() { return (int)posy; }
    int GetID() { return ID; }

};




// Default constructor
Particle::Particle()
: ID(-1),
  posx(0.0),
  posy(0.0),
  velx(0.0),
  vely(0.0),
  age(0),
  GRAVITY(8.91)
{
}

// Advanced constructor
Particle::Particle( int x, int y, double velocity, double angle, int id )
: ID(id),
  posx(x),
  posy(y),
  velx(0),
  vely(0),
  age(0),
  GRAVITY(8.91)
{
    velx = velocity * cos(toRad(angle));
    vely = velocity * sin(toRad(angle));
}



// Update a particle
void Particle::Update( int deltatime, double gravfactor )
{
    // Update position
    posx += velx * deltatime;
    posy += vely * deltatime;
    // Update velocity
    vely += ((GRAVITY * gravfactor) / 6000) * deltatime; // 6000 is a factor obtained experimentally
    // We get older over time...
    age++;
}




Share this post


Link to post
Share on other sites
Trillian    410
- Do not implement class members in the .h header files, use .cpp files!
- Do you really need double precision? float is more than enough in most cases
- You should use a vector class instead of X/Y pairs
- You should allow gravity to be on an arbitrary axis, not only -Y
- Use pre-incrementation unless you need post-incrementation
- erase(iter) followed by iter-- might work for std::vectors, but I doubt it will for other data structures. You might try to find another way of doing this.
- In ParticleSystem::UpdateAll, you should combine your conditionnal statements using ||
- Many occurances of truncation from size_t to int, it's not the end of the world but that's not a good habit (at least use static_cast<> or you'll get compiler warnings).
- Why is Particle::GRAVITY in full caps?
- That experimentally obtained "6000" number looks like a magic number to me
- Increase your particle age by deltaTime to be frame-time independant
- Use a real number for the deltaTime, not an integer
- Might be a good idea to find an alternative to rand(), but again it's not the end of the world.
- You don't seem to be using the particle age for anything

That's a lot of stuff, but you don't have to be that much strict. Your particle system is a bit basic but, even in its current state, it should do the job well for simple games.

Share this post


Link to post
Share on other sites
c4c0d3m0n    100
Quote:
Original post by Trillian
- Do not implement class members in the .h header files, use .cpp files!

I read a tutorial on how to do this, but when i tried converting my Tetris application to this system, I couldn't get it to work... I shall reattempt some other time.
Quote:
- Do you really need double precision? float is more than enough in most cases

You're probably right, I've always used doubles, that's probably why I used them now.
Quote:
- You should use a vector class instead of X/Y pairs

I don't understand how I can use a vector to store two coordinates more effectively.
Quote:
- You should allow gravity to be on an arbitrary axis, not only -Y

This is probably a good idea. Gravity is also on +Y right now btw, by using a negative gravfactor ;)
Quote:
- Use pre-incrementation unless you need post-incrementation

I'm guessing this is relating to the Particle::Update() function.
Quote:
- erase(iter) followed by iter-- might work for std::vectors, but I doubt it will for other data structures. You might try to find another way of doing this.

Please elaborate yourself.
Quote:
- In ParticleSystem::UpdateAll, you should combine your conditionnal statements using ||

Ah yes, good idea. The long list of if's is from the time when I had different debug messages printing to the console for all those conditions
Quote:
- Many occurances of truncation from size_t to int, it's not the end of the world but that's not a good habit (at least use static_cast<> or you'll get compiler warnings).

Surprisingly I don't get any warnings, even though I set my compiler to -pedantic
Quote:
- Why is Particle::GRAVITY in full caps?

Because it's a constant. I always write my constants in full caps. I can't actually make it a constant though, seeing classes don't allow that.
Quote:
- That experimentally obtained "6000" number looks like a magic number to me

It is ;) If I don't use it, the particles will fly down instantly (accelerating at a staggering 8.91 px/ms²). By experimenting I found that the value 6000 allows for something one could experience as natural gravity when using gravfactor = 1.0.
Quote:
- Increase your particle age by deltaTime to be frame-time independant

Good idea.
Quote:
- Use a real number for the deltaTime, not an integer

What is a real number? Why is an intenger not a real number? I'm using integers to represent the amount of ms passed by.
Quote:
- Might be a good idea to find an alternative to rand(), but again it's not the end of the world.

I wouldn't know any alternative.
Quote:
- You don't seem to be using the particle age for anything

Not yet, as stated in the OP ;) I'm planning on using it in the System, where particles die after they reach a certain age.

Quote:
That's a lot of stuff, but you don't have to be that much strict. Your particle system is a bit basic but, even in its current state, it should do the job well for simple games.

It is meant as an experiment really. I'm planning on using it to have some pretty effects in my Tetris game.

Thanks for your time.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this