5
\$\begingroup\$

I have wondered about using the following approach to creating Entity objects in a personal project. What I want is to be able to keep track of all Entity objects that get created, so whenever an instance is created, it should automatically get added to a bookkeeping list.

The approach I thought of using is to create a class that can hand out new Entity objects, rather than allowing them to be created directly. This class is called EntityFactory. It's not the factory pattern though. Basically, I define my Entity base class with a private constructor and made EntityFactory a friend class so that it could instantiate Entity objects and hand them out.

The only downside I can see is that I would have to pass around the EntityFactory object.

Will there be other problems? Is this a bad idea? If so, what alternatives are there to have automatic tracking of all Entity objects that get instantiated.

\$\endgroup\$
4
  • \$\begingroup\$ Is there any reason this is on gamedev.SE instead of StackOverflow? I don't see anything in this question other than 'personal project' that relates to games at all... \$\endgroup\$ Feb 28, 2014 at 0:31
  • \$\begingroup\$ Not only is this not a bad idea, it's what I'd call recommended practice. \$\endgroup\$ Feb 28, 2014 at 0:44
  • \$\begingroup\$ @steven-stadnicki I suppose this could be a more general programming question. In my case I have only wanted to be able to do this for game dev projects though and wanted an answer skewed towards game dev. \$\endgroup\$
    – Jim
    Feb 28, 2014 at 7:47
  • \$\begingroup\$ In my view this is a borderline question (which is why I didn't just migrate it). The theory about factory / "master builder" objects is general, but entity systems tend to be better handled here. \$\endgroup\$
    – user1430
    Feb 28, 2014 at 16:04

2 Answers 2

6
\$\begingroup\$

This is still, essentially, a factory, just not one that creates things via runtime keys. It uses compile-time keys (effectively) instead.

You have touched on the major downside: you'll need to make this factory accessible everywhere you want to be able to create entities. This, however, is also an upside because it means you can control what interfaces are allowed to create objects on a very granular level: if you don't give an interface access to the factory, it can't create new things.

Whether or not you actually need all entities to automatically be tracked somewhere aside, this is a more reasonable pattern for doing so than putting that code in, for example, the entity constructor, since it does not overly pessimize your code against the future need to create entities that aren't tracked (perhaps for testing scenarios, or lazy evaluation, et cetera).

\$\endgroup\$
2
  • \$\begingroup\$ Could you elaborate on the compile-time vs runtime keys distinction? \$\endgroup\$
    – Jim
    Feb 28, 2014 at 18:03
  • 1
    \$\begingroup\$ A runtime key would be something you load from a data file or whatever; the value of the key isn't known at compile time. If you had "CreateObject(string objectTypeName)," that would mean you had runtime keys. Compile-time keys are determined at compile-time; methods themselves are a form of compile-time key, so when you write "factory.CreateBulletObject()" you've selected the key ("bullet") at compile time. \$\endgroup\$
    – user1430
    Feb 28, 2014 at 18:41
-2
\$\begingroup\$

A method which I used for one of my projects is to create a parent class which precedes over all entities and then I used polymorphism to make all the entities the type of the Parent.

Essentially you'll make a list of type Entity and then when you want to modify a specific type then you cast it to its original class type to access any variables that the parent class wouldn't have access to.

You add the specific Entity to the list by casting it to what the parent would class would be. In this case Entity.

Essentially it would look something like this:

Dog d;
Cat c;
Bird b;

Animal AnimalList;

AnimalList.add(static_cast<Animal> d);
AnimalList.add(static_cast<Animal> c);
AnimalList.add(static_cast<Animal> b);

The benefits of this method are you will have a permanent list of objects of the same type and thus will make things easier for, for example, collision detection or updating all of their positions. As you will have a neat list to compare against rather than several lists.

for(int i = 0; i < AnimalList.size(); i++)
{
AnimalList.at(i).update();
AnimalList.at(i).collisionCheck();

if(AnimalList.at(i) == type(Dog))
{
Dog d = static_cast<Dog>AnimalList.at(i);
d.bark(); //Poor example as you'd probably have multiple creatures having a Cry() //method so they could all have the same function like update();
}
}

However it becomes a problem when you want to do checks against specific types. In that case you will have to scour through the list checking against all of the the types to find the right ones. A bypass to this maybe making a indices list for items you want to specifically keep track of. Though I doubt you'll be seeing any performance issues unless you're dealing with a huge list of Entities.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ This doesn't appear to address the question, which was about the pros/cons of a central factory and the ability to automatically maintain a list of entities. Further, your example code, which appears to be C++, is (1) slicing your objects and (2) not achieving dynamic dispatch (which only happens via reference or pointer in C++) and (3) relies on type-switching, which is generally a sign that a polymorphic interface is poorly thought out or designed and not a good practice to be suggesting. \$\endgroup\$
    – user1430
    Feb 27, 2014 at 23:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .