Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

Although I did this a couple of times from scratch, still no solution really fits.

I'm using lua for scripting in my games. Lua holds the "prototypes" of the game elements, that are copied to each entity on it's creation. A prototype represents a class of objects ("Soldier with shotgun"). Also, each prototype may hold event hooks (OnDie, OnSpotEnemy, etc). Clearly it's a prototype, not the object that will be handled.

So, each time a hook is executed, I need to create an object to represent the calling entity (and any entities it interacts with) only for the lifetime of a single script execution. What it means is that a instance of the object lives in lua only for the time needed to run this script.

Simple execution of this idea wasn't much work -- I used lightuserdata to hold the C++ pointer to the entity encapsuled in a being class. To access the fields of the C++ object, I overloaded the metatable of being. However, the fact that the fields of the object are handled by a metatable practically breaks any reasonable implementation of inheritance.

I pondered with the usage of normal userdata, but I'm afraid that the dynamic allocation needed to run each script (some of them being ran each tick in the game loop) are going to ruin performance.

Any suggestions? Or maybe a better solution altogether?

share|improve this question
add comment

2 Answers

up vote 5 down vote accepted

Use composition to model properties of complex entities rather than inheritance. More specifically, use a component-based design rather than an inheritance-based design for your entities. Each component has a known metadata table and your entity's metadata table just exposes a list of components.

share|improve this answer
    
I can't, the C++ representation depends on inheritance, and honestly in this case composition doesn't make sense -- does a NPC include a Mobile which includes a Thing? Or does an Item include a Thing? –  Kornel Kisielewicz Aug 31 '10 at 15:44
    
A Thing has-a Mobile (which I assume means physics) and has-a NPC (which I assume means AI or conversation). I don't know how Item fits into your hierarchy; usually, barring some in-world representation, a Thing has-a Inventory has-a Item; the item itself shares no base class with e.g. the player avatar. –  user744 Aug 31 '10 at 16:37
    
Nope, thing is anything that can be placed on the map, mobile means something that can move (inteface has movement and the map doesn't cache position), NPC means the object can receive NPC events, has stats etc... –  Kornel Kisielewicz Aug 31 '10 at 17:19
    
Item shares a lot with the player avatar -- a position, a map it belongs to, an event mechanism, a name (and other similar stats) and similar reaction to some events -- both are tangible things so both have physical statistics. –  Kornel Kisielewicz Aug 31 '10 at 17:20
2  
I think you will find, as argued in the linked articles, that the C++ code will get considerably cleaner by switching to components. (Your NPC class already sounds close to a blob.) –  user744 Aug 31 '10 at 17:54
show 4 more comments

If your normal userdata solution produces better code, I'd go with that. Lua is so allocation-heavy anyway that you're probably not going to make a significant performance problem for yourself. How many entities and events are you going to have anyway? 10s? 100s? You'll probably still be render-bound*.

And if you do encounter issues, there's ways to mitigate it through the use of different allocators, such as object pools, tiny allocators, and slot allocators.

Without firm profiler evidence either way, I'd always err on the side of cleaner code.

* warning vast over-generalisation based on knowing nothing about your game

share|improve this answer
    
Renderbound entities are not a problem. However the world is a breathing entity and in the background there's a lot of action. Consider the amount of alive entities in the 100000 range. However, the allocator idea seems quite reasonable, considering that each userdata would be the size of a pointer. I think boost has one that could be used out of the box. –  Kornel Kisielewicz Aug 31 '10 at 15:45
1  
You don't even need to use Boost, as they're not hard to implement by hand. A small object allocator is an array of the size of your small object. The freelist is the index of the first free item, and each free item is casted to an int and that is the index of the next free item. When you want to allocate one item, just peel the first one off the list, construct-in-place, and you're done. To free it, just destroy it, write the first free item's index into it, and then set firstfree to the index of the item. –  dash-tom-bang Aug 31 '10 at 18:25
    
You can also just plug in something like tcmalloc (goog-perftools.sourceforge.net/doc/tcmalloc.html) which has better support for small object allocation and see if it helps, no code changes necessary. –  user744 Aug 31 '10 at 18:31
2  
Also, see Modern C++ Design for Alexandrescu's Tiny Allocator. –  tenpn Sep 1 '10 at 7:36
1  
@tenpn that's exactly what I was thinking about. It's a great model to follow and doesn't even require too much mad template skills. –  dash-tom-bang Sep 2 '10 at 0:31
show 1 more comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.