Object Management Question

Started by
6 comments, last by landagen 11 years, 3 months ago

I have a design question. Just for reference, I believe this an implementation of the composite pattern. If not, let me know what pattern this fits into. I have a class called Sprite, ICollidable, IController. I also have Managers, a physics manager and a Render manager. A Collidable object references a sprite, a controller also references a sprite. If I want to turn on collision for a sprite, I just create a Collidable object referencing my sprite and then add it to the physics manager. Same if I want to make it move. I create a controller object and reference the sprite and then add it to the Physics manager (in the controller list. I may move this to a different manager). I would like to be able to have any one class to delete the underlying sprite and all classes referencing the sprite to be informed. I need it to propagate upwards to inform all of the objects that reference it so it knows to not reference it anymore. So for instance, if the Sprite object is deleted, then the ICollidable object needs to be informed who in turn needs to inform the physics manager. The physics manager is not aware of the underlying Sprite object so it cannot be directly informed.

I am just starting down this path and worry about future performance. I know that I should not worry about performance, but this construct is going to be used a lot and I don't want to find out when it is too late. Has anyone used something similar or is there a different way to solve the problem above that may lead to better results?

Some things I have thought of are:

1. Straight inheritance -> better performance, but does not as flexible

2. Checking the state of the object before use -> seems like it would have really bad performance since I will use way more often than I will delete it

3. Treating each object in the hierarchy as a bi-directional linked tree node so that I can traverse up and down to delete all of the objects. -> seems to lose a lot of flexibility and will probably require that each class who wants to participate to inherit from a base class.

I hope my intention is clear.



Advertisement
Well, my best bet is a simple one, and it has no performance hit whatsoever. Also everything would work as you have it right now.Well almost everything.

Create a base component class, that only has a method called Destroy/Dispose whatever you wish.

Then on your sprite class have a list of these components, when you add one it goes into this list, once you destroy the sprite, just call the Dispose/Destroy method from the interface, and each component would clean up after itself.
You get all of the good qualities from your original method, without any performance hit (well minus the inheritance, but you would just call it when you destroy the sprite)

If you need a more detailed explanation I can throw some pseudo code to you. =)

Check out my new blog: Morphexe

1. This is not the composite pattern, or even close to it.

2. 'Everything is a Manager' is a code smell. Here it's maybe not super terrible, but something to consider.

3. Anytime you think 'I want anything to be able to' stop and reconsider.

4. Anytime you think 'I want to also do XYZ when I do W' stop and reconsider.

5. Anytime you use the word 'propogate' in describing a design, stop and reconsider.

All that said, I've seen this sort of design and it can work fine.

6. When talking about performance - measure, don't guess.

Some terminology may help. These terms are not universally agreed upon, but in general:

"entity" - an interactable object within the game 'world'
"sprite" - an instance of rendering information
"bitmap" - aka 'texture' - wrapped (or raw) image data to be used in rendering
"collider" - coordinates and dimensions for use in testing collision against other colliders

(The point I'm driving at here is that you should not be colliding sprites. Colliders collide and they belong to entities, not sprites. (Hopefully.))

The composite pattern would have an Entity class which contains a collider and a sprite. The sprite would contain either a reference to or else an exclusive instance of a bitmap.

The composite pattern is actually very straightforward:
class Thing {
  Part p;
  OtherPart q;
  YAP r;
};
'Thing' composes 'Part', 'OtherPart' and 'YAP' and possibly manages their interactions or relative activities:
class Entity {
public:
  void moveTo(int x, int y) {
    collider.x = x;
    collider.y = y;
    sprite.x = x;
    sprite.y = y;
  }
private:
  Collider collider;
  Sprite sprite;
};
Composition is simply gathering together a set of objects into a container that lets you work with them as a single object.

A POD struct is probably the simplest example of composition.

Using the composite pattern helps keep code manageable because you can compose more and more complex types and still make use of them with ease - an entity being a great example since it will likely end up containing all manner of data through members with members with members, but you can still just:
Entity ent;
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
That is not the composite pattern.

The composite pattern requires that your composite object (that fulfills some interface) contain some (possibly 0, possibly variable) amount of other objects (that fulfill that same interface), allowing you to do the interface's operation with respect to the bundle of objects.

For example, a composite renderable might have a bunch of sprites and when you call render on the composite, it renders all of the sprites. Or when you call move, it moves all of the sprites. Or when you call 'Left' it returns the leftmost boundary of any of the sprites.

Simply using composition does cut it.

This would be a perfect place to use smart pointers, such as boost::shared_ptr and boost::weak_ptr.

http://www.boost.org/doc/libs/1_52_0/libs/smart_ptr/smart_ptr.htm

The problem you have is one of ownership. You have an object (a sprite) that is owned, presumably, by some global list of game objects. Then you have other objects (physics controller, movement controller, etc) that point to your game object, but they dont own it. So:

1. Use a boost::shared_ptr in the list of game objects. This means the list "owns" those objects

2. Use boost::weak_ptr anywhere else that someone needs to point to that object. They dont own the object, but they can reference it if needed.

The way weak_ptrs work is that you have to get a shared_ptr from them in order to access the object. If you try and get a NULL shared_ptr, it means the object was deleted.

So your list of controllers is a list of weak_ptrs. When you go through them each frame, if they give you a NULL shared_ptr, you simply remove them from the list. If not NULL, then you can do your work.

Ownership solved, memory management solved, cleaner design all around.

Simply using composition does cut it.

Ah, I thought they were the same. My mistake. When I've implemented things using that pattern I always just referred to them as 'sets'.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
I agree it doesn't fit with the composite pattern. I am not sure what pattern it follows if any. Not that it is important. I have thought about the shared_ptr route and will investigate that some more. I think I need to re-evaluate what I am trying to accomplish. It seems I may be overcomplicating a simple problem. I will also look into having a container like an Entity class and just publish and subscribe to the events that could cause its destruction and let the consumer of said event handle unregistering and destroying the object. Thanks for the input.


This topic is closed to new replies.

Advertisement