I've always wondered to what extent object orientation is used by videogames, especially huge 3D projects.
I reckon it would be cool that both troll and werewolf inherited its attributes from enemy and overwrote some of them. But maybe classes are too heavy to be practical, I don't know...

How does one quantify (or even objectively qualify) object-orientation? Do you want an answer in Meyers or Dahl-Nygaards?
–
user744Jun 25 '11 at 16:16

Obviously they are so heavy that a heavily OO based language is the industry standard.
–
The Communist DuckJun 25 '11 at 16:29

3

If you mean C++, it was chosen because it's a good language for exploring type-safe generic programming in a speed-conscious way; the few OOP features are obviously an unfortunate misdesign kept for backwards-compatibility only. ;)
–
user744Jun 25 '11 at 17:07

6 Answers
6

To come to your example I will explain my thoughts about Entites in videogames. I won´t discuss the general advantage and disadvantage of objects and classes, neither their whole role in Videogames.

Entities in small videogames are mostly defined by seperate classes, in big games they are often defined in files. There are two general approaches to follow:

Extention:
In your example Troll and Werewolf will extend Enemy, which extends Entity. Entity takes care about the basic things like movement, health etc., while Enemy would state the subclasses as enemies and do other things. (Minecraft follows this approach)

Component based: The second approach (and my favorite) is one Entity class, which has components. A component could be Moveable or Enemy. These components take care of one thing like movement or physics. This method breaks long Extension chains and minimizes the risk of running into a conflict. For example: How can you make non-moveable Enemies, if they inherit from a moveable Character?.

In big video games like World of Warcraft or Starcraft 2 Entities aren´t classes, but sets of data, which specify the whole Entity. Scripting is also important, because you define what the Entity does not in a Class, but in a Script (if it is unique, not things like moving).

I am currently programming an RTS and I take the component based approach with Descriptor and Script files for Entites, Skills, Items and everything else dynamic in the game.

Sounds intersting. However I won't lie, I don't know what a component is in this context. A link would be much appreciated.
–
vemvJun 25 '11 at 19:40

A component is an entity that has the responsibility for a single functionality. The component-based entity will own a component (if is the case) it will not inherit from it. The ownership implies that an entity can be deactivate one of its components changing its behavior. In classic Extension paradigm the behavior is due "belonging to" a super-class. An entity can be a component and a component can be modeled as a class or as a struct if you prefer.
–
FxIIIJun 25 '11 at 21:50

Component (sometimes called Entity systems) - you can search this blog for ideas t-machine.org There are variants but the basic idea is that a component is a special purpose object and your actor ties together a bunch of components, like building a model from Legos.
–
Patrick HughesJun 25 '11 at 21:53

Classes do not involve any run-time overhead. Run-time polymorphism is just calling through a function pointer. These overheads are exceedingly minimal compared to other costs like Draw calls, concurrency synchronization, disk I/O, kernel mode switches, poor memory locality, over-use of dynamic memory allocation, poor choice of algorithms, use of scripting languages, and the list goes on. There's a reason that object orientation has essentially supplanted what came before it, and it's because it's much better.

Dispatching among various polymorphic types is done in a way that gives poor memory locality. Even in the lightest-weight implementations like C++ vtables or Objective-C IMP caching, if you actually use the polymorphism to deal with objects of varying types, you will blow your caches. Of course if you don't use the polymorphism than the vtable stays in your cache or the IMP cached message leads to the correct place, but then why bother? And in Java or C# the cost is heavier, and in JavaScript or Python the cost is heavier still.
–
user744Jun 25 '11 at 16:21

1

@Joe Wreschnig: If you're using those slower languages, then the cost of OO is trivial compared to the other costs such as interpretation/JIT. More importantly, you can theorycraft what you want about poor memory locality, but the fact is that branch prediction, out-of-order execution and similar features on the CPU virtually entirely negate the cost. Else, why is it that so much high-performance software is written using object-orientation?
–
DeadMGJun 26 '11 at 16:31

I'm not sure what you mean by "too heavy," but C++/OOP is the lingua franca of game development for the same good reasons that it is used elsewhere.

Talk of blowing caches is a design issue, not a language feature. C++ can't be too bad since it's been used in games for the past 15-20 years. Java can't be too bad since it's used in the very tight run time environments of smart phones.

Now on to the real question: for many years class hierarchies became deep and started to suffer from problems related to that. In more recent times class hierarchies have flattened and composition and other data-driven designs are being rather than logic-driven inheritance.

It's all OOP and still used as the baseline when designing new software, just different focus on what the classes embody.

I reckon it would be cool that both troll and werewolf inherited its attributes from enemy and overwrote some of them.

Unfortunately this approach to polymorphism, popular in the 90s, has shown itself to be a bad idea in practice. Imagine you add 'wolf' to the enemy list - well, it shares some attributes with werewolf, so you'd want to consolidate those into a shared base class, eg. 'WolfLike'. Now you add 'Human' to the enemy list, but werewolves are sometimes humans, so they share attributes too, such as walking on 2 legs, being able to talk, etc. Do you create a 'Humanoid' common base for humans and werewolves, and do you then have to stop werewolves deriving from WolfLike? Or do you multiply inherit from both - in which case, which attribute takes precedence when something in Humanoid clashes with something in WolfLike?

The problem is that trying and model the real world as a tree of classes is ineffective. Take any 3 things and you can probably find 4 different ways to factor their behaviour into shared and non-shared. This is why many have turned to a modular or component-based model instead, where an object is comprised of several smaller objects that make up the whole, and the smaller objects can be swapped or change to make up the behaviour you want. Here you might have just 1 Enemy class, and it contains sub-objects or components for how it walks (eg. Bipedal vs. Quadrupedal), its methods of attack (eg. bite, claw, weapon, fist), its skin (green for trolls, furry for werewolves and wolves), etc.

This is still completely object-oriented, but the notion of what is a useful object is different from what used to be commonly taught in the text books. Rather than having a large inheritance tree of various abstract classes and several concrete classes at the tips of the tree, you typically have just 1 concrete class representing an abstract concept (eg. 'enemy') but which contain more concrete classes representing more abstract concepts (eg. attacks, skin type). Sometimes these second classes can be best implemented via 1 level of inheritance (eg. a base Attack class and several derived classes for specific attacks) but the deep inheritance tree is gone.

But maybe classes are too heavy to be practical, I don't know...

In most modern languages, classes aren't 'heavy'. They're just another way of writing code, and they usually just wrap the procedural approach you would have written anyway, except with easier syntax. But by all means, don't write a class where a function will do. Classes are not intrinsically better, only where they make the code easier to manage or to understand.

One thing to be aware of is that the concepts of object-oriented code are often more valuable than their implementation in languages. In particular, having to do 1000s of virtual update calls on entities in a main loop can cause a mess in the cache in C++ on platforms like 360 or PS3 - so the implementation might avoid "virtual" or even "class" keywords for the sake of speed.

Often though it will still follow the OO concepts of inheritance and encapsulation - just implementing them differently to how the language does itself (e.g. curiously recursive templates, composition instead of inheritance (the component based method described by Marco)). If the inheritance can always be resolved at compile-time then the performance issues go away, but the code can become a bit hairy with templates, custom RTTI implementations (again the built-in ones are usually impractically slow) or compile-time logic in macros etc.

In Objective-C for iOS/Mac there are similar, but worse problems with the messaging scheme (even with the fancy caching stuff)...

The method that I will be attempting to use mixes class inheritance and components. (First off, I don't make Enemy a class -- I make that a component.) I don't like the idea of using one generic Entity class for everything and then adding the necessary components to flesh the entity out. Instead, I prefer to have a class automatically add components (and default values) in the constructor. Then subclasses add their additional components in their constructor, so the subclass would have its components and its parent class components. For example, a Weapon class would add basic components common to all weapons, and then the Sword subclass would add any additional components specific for swords. I'm still debating about whether to use text/xml assets to define values for entities (or specific swords for example), or to do that all in code, or what the right mix is. This still allows the game to use the code language's type information and polymorphism, and makes ObjectFactories much simpler.

Hey Chris. While sharing your experience and plans is great, it's not really directly answering the question. I think the question is more about how these things are typically done where as you're answering how you plan on doing it. They're similar questions, but not really the same.
–
Byte56♦Jun 30 '13 at 12:56