Sign in to follow this  
daniel_i_l

inheritance problem

Recommended Posts

I'm building a particle engine and an having trouble with inheritance. I have a particle struct that contains information like position and color about ine particle, and a particle engine class that updates all the particles and draws them. It contains a virtual function that controls the details of the update, and so I inheret from it classes like smoke and fire which implement it in a certain way. Heres the header for the engine:
#ifndef PARTICLEENGINE_H
#define PARTICLEENGINE_H

#include "3DMath.h"
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <vector>

using namespace std;

struct  SParticle{
    SParticle();     
    bool	  Active;					
	float	  Life;					
	float	  Fade;	
    //float     Rotation;			
	float	  Red;					
	float	  Green;					
	float	  Blue;	
	float     MultAlpha;
	float     Radius;
    float     RadiusSpeed;		
    float     Rotation;				
	CVector3  Position;					
	CVector3  Direction;						
	CVector3  Gravity;	
    
    bool      ChangeColor;			
};

class  CParticleEngine{
 public:
   //holds all the particles
   vector<SParticle>   m_vParticles;
   int                 m_iNumberOfParticles;
   float               m_fSlowDown;
   
   
   void                InitAllParticles();

   CParticleEngine(int n, CVector3 p);

   CVector3            m_vPosition;
   
  
  void Update(double elapsed_time);
  
  //all entities must implement an init function
  virtual void InitOneParticle(SParticle &particle) = 0;


   CVector3 Vector(){return m_vPosition;}
   float    Number(){return m_vParticles[0].Life;}
};

class Smoke : public CParticleEngine{
  public:
     Smoke(int n, CVector3 p);
     void InitOneParticle(SParticle &particle);
}; 


#endif


and here's the source file:
#include "ParticleEngine.h"
#include "CCamera.h"
#include <gl\gl.h>

extern GLuint  t_Particles[3];
extern int yay;
extern CCamera Camera;
//-------------SParticle--------------
//
//  Constructor for SParticle
//
//------------------------------------
SParticle :: SParticle()
{
  Active = true;					
  Life   = 1.0;					
  Fade   = 0;				
  Red    = 1;					
  Green  = 1;					
  Blue   = 1;
  MultAlpha = 1;
  Radius = 10;
  RadiusSpeed = 0.1;		
  Rotation   = 0;			
  Position   = CVector3(0,0,0);					
  Direction  = CVector3(5,5,5);						
  Gravity    = CVector3(0,0,0);
  
  ChangeColor = false;
}
                           
//------------------CParticleEngine-------------------
//
// Constructor for CParticleEngine
//
//----------------------------------------------------
CParticleEngine :: CParticleEngine(int n, CVector3 p)
{
  m_vPosition = p;
  m_fSlowDown = 2.0;
  for(int i=0; i<n; ++i)
   {              
    // SParticle *particle = new SParticle();
    // m_vParticles.push_back(particle);
       m_vParticles.push_back(SParticle());
   }   
   
   InitAllParticles();
}

//------------------InitAllParticles------------------
//
// initiates all particles
//
//----------------------------------------------------
void CParticleEngine :: InitAllParticles()
{
  for(int i=0;  i<m_vParticles.size(); i++)
   {        
      // m_vParticles[i]->InitParticle(m_vPosition);
      InitOneParticle(m_vParticles[i]);
   }
}

//----------------------Update---------------------
//
//  Updates the particles
//
//-------------------------------------------------
void CParticleEngine :: Update(double elapsed_time)
{
    elapsed_time*=50;
    glBindTexture(GL_TEXTURE_2D,t_Particles[2]);
    glEnable(GL_BLEND);
    glEnable(GL_TEXTURE_2D);
    
    for (int loop=0;loop<m_vParticles.size();loop++)					// Loop Through All The Particles
     {
            glLoadIdentity();
            Camera.Look();
            glTranslatef(0, 10, 0);
			float x = m_vParticles[loop].Position.x;
			float y = m_vParticles[loop].Position.y;
			float z = m_vParticles[loop].Position.z;

// Draw The Particle Using Our RGB Values, Fade The 
//Particle Based On It's Life
		
			
            glColor4f(m_vParticles[loop].Red,
                      m_vParticles[loop].Green,
                      m_vParticles[loop].Blue,
                      m_vParticles[loop].Life/m_vParticles[loop].MultAlpha);
             float radius = m_vParticles[loop].Radius;
			 glTranslatef(x, y, z);
			 glRotatef(m_vParticles[loop].Rotation,0,0,1);
            glBegin(GL_TRIANGLE_STRIP);					
// Build Quad From A Triangle Strip
			    glTexCoord2d(1,1); glVertex3f(radius,radius,0); 
				glTexCoord2d(0,1); glVertex3f(- 
                                                    radius,radius,0); 
				glTexCoord2d(1,0); glVertex3f(radius,-
                                                              radius,0); 
				glTexCoord2d(0,0); glVertex3f(-radius,-
                                                              radius,0); 
			glEnd();										
			m_vParticles[loop].Position.x += 
  elapsed_time*m_vParticles[loop].Direction.x/(m_fSlowDown*1000);
			m_vParticles[loop].Position.y += 
  elapsed_time*m_vParticles[loop].Direction.y/(m_fSlowDown*1000);
			m_vParticles[loop].Position.z += 
  elapsed_time*m_vParticles[loop].Direction.z/(m_fSlowDown*1000);

			m_vParticles[loop].Direction.x += 
  elapsed_time*m_vParticles[loop].Gravity.x;			
			m_vParticles[loop].Direction.y += 
  elapsed_time*m_vParticles[loop].Gravity.y;			
			m_vParticles[loop].Direction.z += 
  elapsed_time*m_vParticles[loop].Gravity.z;			
            m_vParticles[loop].Radius += elapsed_time*m_vParticles
  [loop].RadiusSpeed;
            
            m_vParticles[loop].Life  -= elapsed_time*m_vParticles[loop].Fade;		
  
            if (m_vParticles[loop].Life<=0.0f)					// If Particle Is Burned Out
			{
				
			InitOneParticle(m_vParticles[loop]);
			}
          
   }//loop
}
                              
Smoke :: Smoke(int n, CVector3 p):CParticleEngine(n, p){}

void  Smoke :: InitOneParticle(SParticle &particle)       
{
  particle.Active = true;					
  particle.Life   = 1.0;					
  particle.Fade   = (rand()%150)/1000.0f + 0.002;
  particle.MultAlpha = 2.5;			
  particle.Radius    = 10;
  particle.RadiusSpeed = (rand()%150)/1000.0f + 0.002;
  float col = (rand()%600)/1000.0f;

  particle.Red   = col;	// Select Red Rainbow Color
  particle.Green = col;	// Select Red Rainbow Color
  particle.Blue  = col;  
   
  particle.Rotation  =  (rand()%100)*3.6;  
  //Position  = p;//CVector3(20,20,20);
  particle.Direction = CVector3(float((rand()%50)-26.0f)*0.0f,
                       float((rand()%20)+10.0f)*70.0f,
                       float((rand()%50)-26.0f)*0.0f); 
  particle.Position = m_vPosition + CVector3(float((rand()%50)-26.0f)*0.15f,
                                              float((rand()%20)+10.0f)*0.0f,
                                              float((rand()%50)-26.0f)*0.15f); 
  //CVector3 Direction = CVector3(10,10,0); 
  particle.Gravity   = CVector3(-5,0,0);  
}      




now when I call the constructor like this: Smoke Smoke(1000, CVector3(80,120,80)); I get some kind of runtime error/crash. if I erase the InitAllParticles(); from the ctor then it doesn't crash. Also, if I make the InitOneParticle(SParticle &particle) not virtual, but rather part of CParticleEngine and call the ctor: CParticleEngine ParticleEngine(1000, CVector3(120,120,180)); then it works fine? What is the problem? Thanks.

Share this post


Link to post
Share on other sites
You could have just bumped your other thread you know.

Anyway, I see the problem anyway. You are calling a virtual function from the base class' constructor. Because the derived class hasn't been constructed yet (the base class' constructor is called first) the vtable holds a pointer to the base class' function... which happens to be pure virtual. Boom, crash, etc.

Share this post


Link to post
Share on other sites
You've got other issues too, btw. You prototype initOneParticle without the virtual, then prototype it with virtual and as pure virtual, and then you define a body for it anyway. Isn't your compiler giving you some warnings about this?

Share this post


Link to post
Share on other sites
Oh, I was reading InitAllParticles when I thought that. Forget about it. It's actually the call in the constructor to initallparticles that calls the virtual and makes it crash. Instead; just remove it from the constructor and call it seperatly in the client code, or have update initialize the first time it's called, or something like that.

Share this post


Link to post
Share on other sites
Thanks, it works now. One more question, I'm pretty new to making things with inheritance, is the overall structure of the PE good, are there anythings I should fix/improve?
Thanks.

Share this post


Link to post
Share on other sites
Not really my area of expertise. It looks fugly to me, but I havn't the time nor desire to write you a better one myself.

Share this post


Link to post
Share on other sites
Hard to say. I just don't like it. I'd do something more like


class Particle
{
private:
//data
public:
static const int UPDATE_DESTROY = 0;
static const int UPDATE_KEEP = 1;
int update();
};

class Emitter
{
public:
virtual Particle emit(/*stuff here?*/);
};

class ParticleSet
{
private:
std::list<Particle> particles;
Emitter* emitter;
ParticleSet();
public:
explicit ParticleSet(Emitter* e) : emitter(e) { assert(e); }

void update()
{
if (should emit more particles) particles.push_back(emitter->emit(/*stuff*/));
for (std::list<Particle>::iterator I = particles.begin(); I != particles.end();)
{
if (I->update == Particle::UPDATE_DESTROY)
I = particles.erase(I);
else
++I;
}
}
};



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