I don't use a list as much as possible. They have a tendency to slow your particle system down (cache misses). Same with polymorphism in general (vtable).
However, you could make things polymorphic and fast by using something like this system.
Enemy header:
/******************************************************************************
*******************************************************************************
Bubble Fight EX
relminator
http://rel.betterwebber.com
Cancer class
*******************************************************************************
******************************************************************************/
#include <nds.h>
#include <vector>
#include "EntityContainer.h"
#include "StarFighter.h"
#ifndef BLOB_H
#define BLOB_H
//------------------------------------------------------------------------------
// Blob Enemy
//------------------------------------------------------------------------------
class Blob {
public:
friend class BlobContainer;
Blob();
~Blob();
void Update();
private:
s32 x;
s32 y;
s32 Dx;
s32 Dy;
s32 Sx;
int Radius;
int Frame;
int Counter;
bool Active;
EN_DRAW_MODE DrawMode;
};
//------------------------------------------------------------------------------
// Blob Container
//------------------------------------------------------------------------------
class BlobContainer : public EntityContainer
{
public:
BlobContainer( int Palette, glImage* const Sprites );
~BlobContainer();
virtual void UpdateEntities();
virtual void DrawEntities();
virtual bool Collide( StarFighter &Star );
void Spawn( int _x, int _y, s32 speed, int _radius );
virtual int NumEntities()
{
return numEntities;
}
private:
int numEntities;
glImage *Images;
int ColorTable;
std::vector<Blob> Blobs;
};
#endif // BLOB_H
Enemy Class
/******************************************************************************
*******************************************************************************
Bubble Fight EX
relminator
http://rel.betterwebber.com
Cancer class
*******************************************************************************
******************************************************************************/
#include "Blob.h"
#define MIN_X ( -20 << 12 )
#define MIN_Y ( -18 << 12 )
#define MAX_BLOBS 16
//------------------------------------------------------------------------------
// Blob Enemy
//------------------------------------------------------------------------------
Blob::Blob()
{
Frame = 0;
Active = false;
DrawMode = EN_NORMAL;
}
Blob::~Blob()
{
}
void Blob::Update()
{
Sx += Dx;
x = Sx + sinLerp( Counter * 230 ) * Radius;
if( x < MIN_X )
Active = false;
Counter++;
// animate
if( ( Counter & 3 ) == 0 )
{
Frame = (Frame + 1) & 3;
}
}
//------------------------------------------------------------------------------
// Blob Container
//------------------------------------------------------------------------------
//--------------------------------------
// Ctor and Dtor
//--------------------------------------
BlobContainer::BlobContainer( int Palette, glImage* const Sprites )
{
ColorTable = Palette; // init needed data for drawing
Images = Sprites;
Blobs.resize( MAX_BLOBS/2 ); // 1/2 of max (speed of iteration)
Blobs.reserve( MAX_BLOBS ); // reserve max for speed. No need to do this for enemies
}
BlobContainer::~BlobContainer()
{
Blobs.clear(); // clear the bullets
}
//--------------------------------------
// Virtual Functions
//--------------------------------------
void BlobContainer::UpdateEntities()
{
std::vector<Blob>::iterator iter;
for( iter = Blobs.begin(); iter != Blobs.end(); ++iter )
{
if( iter->Active )
iter->Update();
}
}
void BlobContainer::DrawEntities()
{
glColorTable( GL_RGB16, ColorTable );
numEntities = 0;
std::vector<Blob>::iterator iter;
for( iter = Blobs.begin(); iter != Blobs.end(); ++iter )
{
if( iter->Active )
{
numEntities++;
if( (iter->DrawMode == EN_WHITE) )
{
iter->DrawMode = EN_NORMAL;
glColorTable( GL_RGB256, Palettes::Instance()->Green() );
glSprite( (iter->x >> 12) - 19, (iter->y >> 12) - 18,
GL_FLIP_NONE, &Images[iter->Frame]
);
glColorTable( GL_RGB16, ColorTable );
}
else
{
glSprite( (iter->x >> 12) - 19, (iter->y >> 12) - 18,
GL_FLIP_NONE, &Images[iter->Frame]
);
}
}
}
}
bool BlobContainer::Collide( StarFighter &Star )
{
std::vector<Blob>::iterator iter;
for( iter = Blobs.begin(); iter != Blobs.end(); ++iter )
{
if( iter->Active )
{
int rad2 = 16 * 16;
int cx = (iter->x >> 12) - (Star.x >> 12);
int cy = (iter->y >> 12) - (Star.y >> 12);
if( ( (cx * cx) + (cy * cy) ) < (rad2 * (1+Star.IsBursting())) )
{
if( Star.IsBursting() && (iter->DrawMode == EN_NORMAL) )
{
if( (iter->Counter & 1) ) iter->DrawMode = EN_WHITE;
}
return true;
}
}
}
return false;
}
//--------------------------------------
// Non-Virtual Functions
//--------------------------------------
void BlobContainer::Spawn( int _x, int _y, s32 speed, int _radius )
{
bool SlotFull = true; // value to check if all the slots are occupied
std::vector<Blob>::iterator iter;
for( iter = Blobs.begin(); iter != Blobs.end(); ++iter )
{
if( !iter->Active ) // insert a bullet on a free slot
{
iter->Sx = _x << 12;
iter->y = _y << 12;
iter->Dx = speed;
iter->Dy = 0;
iter->Active = true;
iter->Frame = 0;
iter->Counter = 0;
iter->Radius = _radius;
SlotFull = false; // there's a free slot so we dont execute the code below
break;
}
}
// All the slots are full
// Only push back a bullet if the slot is full and we have less than numbullets
if( SlotFull && (Blobs.size() < MAX_BLOBS) )
{
Blob Blob;
Blob.Sx = _x << 12;
Blob.y = _y << 12;
Blob.Dx = speed;
Blob.Dy = 0;
Blob.Active = true;
Blob.Frame = 0;
Blob.Counter = 0;
Blob.Radius = _radius;
Blobs.push_back(Blob);
}
}
Notice that BlobContainer is a "friend" of Blob.
Then, by containing the container in this abstract class...
/******************************************************************************
*******************************************************************************
Bubble Fight EX
relminator
http://rel.betterwebber.com
EntityContainer class
*******************************************************************************
******************************************************************************/
#include "StarFighter.h"
#include "Palettes.h"
#ifndef ENTITYCONTAINER_H
#define ENTITYCONTAINER_H
enum EN_DRAW_MODE
{
EN_NORMAL = 0,
EN_COLOR,
EN_WHITE
};
class EntityContainer
{
public:
virtual void UpdateEntities() = 0;
virtual void DrawEntities() = 0;
virtual bool Collide( StarFighter &Star ) = 0; // should also contain SFX and Explosion classes
virtual int NumEntities() = 0;
};
#endif // ENTITYCONTAINER_H
Updating and everything is easier.
// Enemy Containers
CancerContainer CancersC( CancerTexPal, CancerImages );
MetroidContainer MetroidsC( MetroidTexPal, MetroidImages );
BlobContainer Blobs( BlobTexPal, BlobImages );
TentakillContainer Tentakills( TentakillTexPal, TentakillImages );
CentipedeContainer Centipedes( CentipedeTexPal, CentipedeImages );
SparkyContainer Sparkies( SparkyTexPal, SparkyImages );
RotoSparkContainer RotoSparks( SparkyTexPal, SparkyImages );
std::vector<EntityContainer*> Enemies;
// order of drawing is from centipedes to tentakills
Enemies.push_back( &Centipedes );
Enemies.push_back( &Sparkies );
Enemies.push_back( &RotoSparks );
Enemies.push_back( &MetroidsC );
Enemies.push_back( &CancersC );
Enemies.push_back( &Blobs );
Enemies.push_back( &Tentakills );
// update all enemy types
std::vector<EntityContainer*>::iterator iter;
for( iter = Enemies.begin(); iter != Enemies.end(); ++iter )
{
(*iter)->UpdateEntities();
}
This way, you limit your vtable access per enemy type rather than per enemy. It even runs fast on the Nintendo DS.
Oh yeah, I don't "delete" but "deactivate", that way your std::vector does not resize here and there.
Here it is in action:
http://rel.betterwebber.com/junk.php?id=119If you need an emulator, you can google "no$gba".
The idea behind this system is to combine both OOP and DoD (Data Oriented Design)