3

I'm working on a school project developing a game. We use an engine made by one of the teams we have. The build-up of the engine is unclear to me and seems an anti-pattern. However, it seems that no one can make the design choices clear to me. The engine is supposed to use a "Component-based" design but I don't see it. Below is the code of both the Component, Composite and Entity class. My question in short is this: is this code using a valid design pattern or is it overcomplicated just for the sake of 'implementing a design pattern', thereby causing an antipattern?

Component.cpp:

#include "Engine\Component.h"
#include "Engine\Composite.h"

Component::Component(Composite* parent)

{
    this->parent = parent;
}

Component::~Component()
{
}

Entity.cpp

#include "Engine\Entity.h"
#include "Engine\Game.h"


Entity::Entity(Composite* parent):Composite(parent)
{
    this->mass = 1;
    node = NULL;
}

void Entity::update()
{
    Composite::update();

    this->angularVelocity += this->angularAccelaration;
    this->orientation += this->angularVelocity;

    this->accelaration = (1 / this->mass) * this->force;
    this->velocity += this->accelaration;
    this->position += this->velocity;
    if (node != NULL)
    {
        this->node->setPosition(this->position);
        this->node->setRotation(this->orientation);
    }
}

void Entity::draw()
{
    Composite::draw();

    if (node == NULL) return;
    if (!this->visible)
    {
        this->node->setVisible(false);
        return;
    }
    this->node->setVisible(true);

    this->node->render();
}

void Entity::createNode(std::string modelPath)
{
    // Get the mesh
    irr::scene::IAnimatedMesh* mesh = Game::getSceneManager()->getMesh(modelPath.c_str());

    // Create model entity
    this->node =  Game::getSceneManager()->addMeshSceneNode( mesh );
    this->node->setMaterialFlag(EMF_FOG_ENABLE, true);
}

Entity::~Entity()
{
    Composite::~Composite();
    if (node != NULL)
    {
        node->drop();
    }
}

Composite.cpp

#include "Engine\Composite.h"

Composite::Composite(Composite* parent):Component(parent)
{
}


Composite::~Composite()
{
    for (std::list<Component*>::iterator i = components.begin(); i != components.end(); ++i)
    {
        delete (*i);
    }
    components.clear();
}

void Composite::handleMessage(unsigned int message, void* data)
{
    for (std::list<Component*>::iterator i = components.begin(); i != components.end(); ++i)
    {
        (*i)->handleMessage(message, data);
    }
}

void Composite::update()
{
    for (std::list<Component*>::iterator i = components.begin(); i != components.end(); ++i)
    {
        (*i)->update();
    }
}

void Composite::draw()
{
    for (std::list<Component*>::iterator i = components.begin(); i != components.end(); ++i)
    {
        (*i)->draw();
    }
}

void Composite::addComponent(Component* component)
{
    components.push_back(component);
}

void Composite::removeComponent(Component* component)
{
    components.remove(component);
    delete component;
}

And the next piece of code is Player.cpp using both composite and entity as a hybrid type of object (I really don't get the logic).

Player.cpp

#include "Player.h"
#include "Messages.h"
#include <iostream>

Player::Player(Composite* parent) : Entity(parent)
{
    createNode("../assets/sydney.md2");
    //i = 0;
    //v3f = vector3df(0,0,0);
    /*networker = new NetworkComponent();
    addComponent(networker);
    networker->registerVar(&i);
    networker->registerVar(&v3f);*/
}

void Player::update() {
    Composite::update();
    //std::cout<<i<<std::endl;
    //std::cout<<"vectorx="<<v3f.X<<"\n";
}

void Player::handleMessage(unsigned int message, void* data) {
    switch(message) {
        case DAMAGE: /* Do something */;
    }
    delete data;
}

Player::~Player()
{
    Entity::~Entity();
}

I don't believe this is a component-based design at all. Shouldn't Entity be deleted and only Composite and Component be used. Shouldn't the component base class be empty and never used directly? Like a component called 'Rigidbody' holding a data structure for rigidbody data and some functions overriding a fully virtual component base class?

Ivan Aksamentov - Drop
  • 12,860
  • 3
  • 34
  • 61
RB-Develop
  • 196
  • 1
  • 9
  • Thanks for the edit Nathaniel Ford, it should make it a bit more straight-forward :) – RB-Develop Apr 08 '13 at 21:48
  • I don't see how game component design and the composite pattern are the same thing. Should `Player` be a component as well, because in composite pattern, it should be. – yngccc Apr 08 '13 at 22:54
  • @yngum I thought the 2 were completely different indeed. Is the code a mix of 2 different design patterns? If 'Player' is a component, then what would inherit from it? Shouldn't the component be something like 'Controllable' fro which 'Player' will inherit? At least that's how I understand composite right now. – RB-Develop Apr 08 '13 at 23:12

1 Answers1

2

The posted code is a variant of a the composite pattern. This design pattern is structural pattern used to allow clients to treat individual objects and complex objects, such as those composed of multiple objects, in a uniform manner. For instance, a rendering loop can iterate over a collection of objects, calling draw() on each of them. As this is a structural pattern, it is difficult to subjectively answer if this is instance of overengineering, as it would require examining more class hierarchies and architecture.

However, neither the class naming conventions of Component and Composite nor the use of the composite design pattern implies this is a "component-based" design. I was not familiar with the game programming component pattern, but it essentially appears to be the strategy pattern with state coupled within the algorithm class, resulting in a simplified interface between strategy and context. In either case, these two patterns are behavioral patterns that accomplish interchangeable and encapsulated algorithms. Therefore, the posted code does not implement a "component-based" design, as neither the Component, Composite, Entity, nor Player class provides a means to encapsulates the algorithms in an interchangeable manner. For example, Entity::update() will always calculate the position in the same manner. This coupling requires the Entity class hierarchy to be expanded if Entity needs to use a different physics model (consider the case of an Entity warping to a planet with a different set of physics), rather than delegating to a Physics hierarchy of classes that encapsulate the algorithms.

Tanner Sansbury
  • 51,153
  • 9
  • 112
  • 169
  • I see what you mean, thanks for the insight. In that case I'm asking if the design is valid. I thought that a Composite and a Entity are the same thing: a collection of Components which add the functionality to an object in an abstract way. – RB-Develop Apr 08 '13 at 22:35
  • 1
    @RB-Develop: I have updated my answer based on changes to the original question. The actual question is fairly subjective, but hopefully the answer provides some clarification that will allow you to make the decision for yourself. – Tanner Sansbury Apr 16 '13 at 04:53
  • Thanks for the update, it does make it more clear for me. It turns out they were going for a 'Component Based Entity System' by using just Component and Entity (seems like the strategy pattern with a fancy name). Later a teacher mentioned Composite would be a good idea so they just added it. I don't think it's overengineered, I think it's just a broken design. – RB-Develop Apr 17 '13 at 14:01