Jump to content

  • Log In with Google      Sign In   
  • Create Account


Strewya

Member Since 17 Dec 2009
Offline Last Active Today, 09:24 AM

Posts I've Made

In Topic: How do you manage object pools in your engine/game?

12 September 2014 - 06:07 AM

 

What Nemo Persona says, constantly newing and deleting objects is a bad idea if your game should be running for a longer period of time. Each new usually translates into a context switch from application/user mode into kernel mode for the OS, which then needs to allocate the requested amount of memory, and then switch back to user mode, which might take a long time depending on fragmentation and platform specifics.

 

ObjectPools are usually used to avoid new and delete for most of your use cases. You allocate a large memory buffer (either with new or malloc), and then manually hand out that memory to the rest of your application. That way you limit yourself to a low number of memory allocations, and instead only care about memory initialization (with placement new, for example).

 

The simplest way to make an ObjectPool is to use a vector for your planned type (i.e. std::vector<Ogre>), make a simple wrapper class that tracks which indices were "allocated" (more like requested to be used), and that's it. If you know for sure you will never need more than X amound of your objects, you can even just use an array (Ogre[1000]), and keep the same wrapper interface, without the user of that interface being none the wiser, except the fact that it won't be able to allocate more than 1000 Ogres.

Thanks, good answer.

 

More or less this is the way I was explaining. The problem with a single vector is reallocation handling. This is why I suggested to use an array of pools. This way reallocs of vectors won't be proced.

 

Cheers.

 

 

You should note that if you reference the objects in the pool by index within the vector, than you don't need to care about the vector moving the data around in memory. This is the strength of indices, with the small drawback of one additional indirection to actually get the data.

 

And the usage of these pools should also be as simple as possible. If you need a pool for Ogres, make an instance if ObjectPool<Ogre> m_ogrePool in your game class, or some other logical place. Don't make the pools static, nor singletons, as you lock yourself from being able to make different pools for different levels or maps.


In Topic: How do you manage object pools in your engine/game?

12 September 2014 - 05:32 AM

What Nemo Persona says, constantly newing and deleting objects is a bad idea if your game should be running for a longer period of time. Each new usually translates into a context switch from application/user mode into kernel mode for the OS, which then needs to allocate the requested amount of memory, and then switch back to user mode, which might take a long time depending on fragmentation and platform specifics.

 

ObjectPools are usually used to avoid new and delete for most of your use cases. You allocate a large memory buffer (either with new or malloc), and then manually hand out that memory to the rest of your application. That way you limit yourself to a low number of memory allocations, and instead only care about memory initialization (with placement new, for example).

 

The simplest way to make an ObjectPool is to use a vector for your planned type (i.e. std::vector<Ogre>), make a simple wrapper class that tracks which indices were "allocated" (more like requested to be used), and that's it. If you know for sure you will never need more than X amound of your objects, you can even just use an array (Ogre[1000]), and keep the same wrapper interface, without the user of that interface being none the wiser, except the fact that it won't be able to allocate more than 1000 Ogres.


In Topic: Need opinions on combat system

06 September 2014 - 04:55 AM

Is your game playable?
Do you have an option for prototyping the combat mechanic in any way?

I think maybe you should start with the first idea that springs to mind, try it out, and see if you're having fun with it. Try getting some of your friends or coworkers to try it out and see if they're having fun with the combat.

Things that sound good on paper might not be good when implemented, and vice versa. The only way to get a good combat system is to make something, try it, and change or improve it, and repeat the whole process until you're satisfied. And the fact that combat is very dependent on the rest of your game makes it even harder to suggest ideas or improvements.

In Topic: ECS based system - Entity Manager with templates

05 September 2014 - 02:39 AM

Just a word of caution to be careful returning raw pointers to objects.  My general preference and what I have always been taught is that an API should return a weak pointer to the object indicating lack of ownership or at the very least have the API return value be a reference rather than the raw pointer like as follows.

//
PositionComponent& position = mEntityManager.GetComponent<PositionComponent>(entityId);
//
This way, it's pretty clear that whatever the calling code is that is getting position doesn't own the object but merely holds a reference to it.  Of course, there is nothing stopping the user of the position from turning it into a pointer and calling delete on it, absolutely.  But the above API is more self documenting and is clearer about the ownership of the object.

 

 
A reference is good if you can guarantee the thing you're getting exists, always, no matter what.
What do you return if there is no component for the entityId you're passing? Say, you're trying to get a DamageComponent from an entityId representing a tree?
Returning raw pointers is fine, as long as you treat them as weak pointers, which should in no way be stored anywhere, but are just temporarily retrieved do to some operations and then discarded within the same scope they were retrieved. Transfer of ownership should ideally be done by returning a unique_ptr.
 
 

I have a similar approach in my ECS. To prevent my EntityManager from comparing component types every time, I implemented my ComponentPools with static members only. This way my EntityManager just has to call  

ComponentPool<T>::getComponent(someId);  
and done. No need to touch this class because I need another component type (like in Strewyas suggestion). Please tell me that this is not a very bad design biggrin.png
 
I have a question though. I do have a base component class just storing the ID. This is because when one system works with a component and needs to find a component of another type with the same ID (because some interaction between those two has to occur in some special cases) I have to know the ID somehow. Is there a better way of getting the ID?
I hope you guys understand what I am trying to say, my english is not the best wink.png
 
Jeay first post.

 

Welcome to GD.net smile.png
 
Having the component pool as a static class (static members and static functions) stops you from having multiple instances of that same component pool for different purposes, and stops you from spacing/scoping the same component type. See this video from Sean for the idea behind spaces. It's much better to design your classes as something you actually instantiate, and if you need one, make an instance of it in you Game class, or Engine class, or Level class, etc.
 
One example idea is if you can make the component pools to have a parent pool for the same component type. Then have one main ComponentPool<T> m_positions in your Game class, and a child ComponentPool<T> m_positions in your Level class. When you getComponent(entityId) from the level-scope m_positions, if there is no entry in it, it can automatically ask it's parent (which in this example is the game-scope m_positions) if he has an entry, and return nullptr only if the topmost parent has no entry. It's a neat little idea, but shows how having the ComponentPools be static classes restricts you from doing cool stuff.
 
About your ID question, i'm assuming the ID is the entityId? There's nothing wrong with storing the entityId in the component itself to denote it's owner. You need a mapping between the owning entity and it's components anyway. If your systems are never actually referencing the ComponentPools (and thus not getting components from pools by calling a get(entityId) method), but rather directly store pointers/references to the components themselves, then storing the entityIds inside the component is a valid (and potentially required) option. If the systems are referencing the pools and calling a get() method, than the entityId inside the components might be superfluous, since you have the entityId already. I emphasize 'might' because it completely depends on the rest of your architectural decisions for the classes and code flow.


In Topic: Upgrading a function that loads config files.

21 August 2014 - 01:01 AM

Personally, i use Lua for config files. Since i use it for scripting anyway, i don't see a reason why i wouldn't also use it for configuration.


PARTNERS