In lieu of a typical implementation of entity-component systems, I've gone the data-oriented route described by Jason Gregory in Game Engine Architecture. This works really well for common properties that need to be present in practically every entity, like position, model information, and health.
// Common properties
namespace Entity
{
Vector position[MAX_ENTITIES];
int health[MAX_ENTITIES];
Model::ID model[MAX_ENTITIES];
}
But what about when it comes to specific information like character status, AI behavior modifiers, and NPC descriptions? Only a handful of entities need this kind of information: who would expect a barrel to give out quests? It needs to be discrete for each entity, so flyweighting is ruled out.
// Rare properties
namespace Entity
{
// Character stats
int strength[MAX_ENTITIES];
int intelligence[MAX_ENTITIES];
int charisma[MAX_ENTITIES];
// AI behaviour
int aggressiveness[MAX_ENTITIES];
int recklessness[MAX_ENTITIES];
}
Should I just grit my teeth and make every entity a blob of the same data? Or is there something else I can do to create distinctions between entity types?
Edit:
Here's a method I'm now considering. Hopefully I can program the systems to make use of this layout while still avoiding memory problems.
// Common entity data
bool Entity::active [MAX_ENTITIES];
Vector Entity::position [MAX_ENTITIES];
Quaternion Entity::orientation [MAX_ENTITIES];
Vector Entity::scale [MAX_ENTITIES];
// Entity handles
Model::ID Entity::model [MAX_ENTITIES]; // Index into the Model::X properties
NPC::ID Entity::npc [MAX_ENTITIES]; // Index into the NPC::X properties
Script::ID Entity::script [MAX_ENTITIES]; // Index into the Script::X properties
Status::ID Entity::status [MAX_ENTITIES]; // Index into the Status::X properties
// Models
Material::ID Model::material [MAX_MODELS];
Mesh::ID Model::mesh [MAX_MODELS];
Skeleton::ID Model::skeleton [MAX_MODELS];
// Materials
Texture::ID Material::colorMap [MAX_MATERIALS];
Color Material::diffuse [MAX_MATERIALS];
Texture::ID Material::normalMap [MAX_MATERIALS];
Color Material::specular [MAX_MATERIALS];
Shader::ID Material::shader [MAX_MATERIALS];
// You can see where this is going...
The benefits of this are that you only need to specify the data for the components you need, and it works well with my resource systems (which operate via handles). It also allows me to process each mesh in the same way, each animation in the same way, etc.
I'll post more if I run into any issues.