inheritance problem

Started by
7 comments, last by Deyja 17 years, 11 months ago
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->InitParticle(m_vPosition);
      InitOneParticle(m_vParticles);
   }
}

//----------------------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.
"We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare. Now, thanks to the internet, we know this is not true." -- Professor Robert Silensky
Advertisement
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.
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?
Thanks, so what do I do?
EDIT: I didn't understand your second reply, were did I prototype InitOneParticle without the virtual?
"We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare. Now, thanks to the internet, we know this is not true." -- Professor Robert Silensky
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.
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.
"We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare. Now, thanks to the internet, we know this is not true." -- Professor Robert Silensky
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.
Whats "fugly" about it?
Thanks.
"We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare. Now, thanks to the internet, we know this is not true." -- Professor Robert Silensky
Hard to say. I just don't like it. I'd do something more like

class Particle{private:   //datapublic:   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;      }   }};

This topic is closed to new replies.

Advertisement