When to use polymorphism

Started by
16 comments, last by Jason Z 10 years, 3 months ago

One place where polymorphism is used to model "game objects" in simple games. Such games might have an abstract "Game Object" or "Entity" class, from which all objects in the game derive from. This might have a handful of virtual functions, such as one to advance the object's state by one frame, and another to draw the object. Much of the higher level code can be written in terms of these game objects, the exact type of which is irrelevant. From the game's point of view, a Kitten and a Space Marine are essentially the same, they both need to be moved every so often, and they both need to be displayed.

In complex games, such as AAA games, a simple model like the above is not used. One reason is the number of classes that would be required becomes too much. Another, is that handling object specific behaviour may be delegated to a script files that are loaded at runtime rather than compiled into the executable.

Another place I see people using polymorphism is for managing the main menu, settings, running game and pause screens, etc. A class might be created called "GameMode" or "GameState". A concrete subclass could be created for a the MainMenu, PlayingGame, PauseScreen, and so forth. Much like the game objects, these might some virtual functions to update and render. They might also need functions to react to input events. Finally, a mechanism for transitioning to the next state is needed. One way to do this is to have the update() function return a smart pointer to the next mode or state, if a transition is to be made. If no transition is needed, then no pointer is returned.

This can sometimes be modelled as a simple GameMode/GameState enum, which dispatches to various state-specific functions, avoiding the need to create a class hierarchy.

In general, the more important thing is to know when to avoid polymorphism. Programmers who are not experienced in object oriented programming tend to over-use inheritance. While mostly harmless, in some cases misusing inheritance can degrade the code quality. In most games, there wouldn't be dedicated Cat and Dog classes. These game objects typically are quite similar for most intents and purposes, the differences are not in the actual game object behaviour but in their data.

Even a moderate sized game might instead have a general Animal class rather than specific sub-classes. The Animal class could take a variety of arguments to the constructor including what texture and meshes it should use, which sounds it will play and what speed and ferocity it has. This data can then be easily moved into a file, which the game loads. This would allow the game designer to quickly tweak how fast a cat runs, without needing to recompile the entire game executable. This flexibility would allow you to bring your game to play test at a friend's house, where when you realise during the test that cats are too slow and are not correctly balanced, you can change the value there and then and test that the new one is better.

A counter example might be if the game models the animals in such detail that each class would have unique behaviour, for example, a cat landing on their feet after a fall, but a dog would not. In this case, it may be preferable to have two classes to handle this, than to try treat this as data (e.g. a "will_land_on_feet_following_fall" boolean).

As you can see, there is no absolute right answer. Coming up with and evolving designs for these scenarios and more is a skill that you hone by making bigger and bigger games. What works for Pong will often not work for GTA XXVII, and overengineering the code for a simple game wastes lots of time that could be spent making the actual gameplay more fun, making better assets or recruiting artists, all of which would be more valuable to the player.

Advertisement


In which cases I should use polymorphism ?

When the behavior of the class must change at run-time.

If you know you will have dogs & cats then can keep a list of dogs separate from a list of cats.

If you know you will have dogs, cats, and "some other animals" then you need polymorphism. It is designed to handle that ambiguity.

The usage of polymorphism has evolved into an Interface / Implementation pairing. You design a completely abstract interface, which is a contract of what the implementation must do. It is more than function signatures, it is a set of guaranteed behavior. (This is not how you must or should use it, that's just how it is commonly done. C++ gives you some more choices.)

- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara

One place where polymorphism is used to model "game objects" in simple games. Such games might have an abstract "Game Object" or "Entity" class, from which all objects in the game derive from. This might have a handful of virtual functions, such as one to advance the object's state by one frame, and another to draw the object. Much of the higher level code can be written in terms of these game objects, the exact type of which is irrelevant. From the game's point of view, a Kitten and a Space Marine are essentially the same, they both need to be moved every so often, and they both need to be displayed.

In complex games, such as AAA games, a simple model like the above is not used. One reason is the number of classes that would be required becomes too much. Another, is that handling object specific behaviour may be delegated to a script files that are loaded at runtime rather than compiled into the executable.

So I assume that AAA games use scripts to do some specific object behavior. But for those scripts I assume they would still use some objects ?

Unity 3D uses "Game Object". So does Unity 3D fall into this AAA ? I mean are there any games that are AAA and are built in it ?

Polymorphism is used in order to treat a set of objects equally without regard to implementation details. Interfaces are used in order to treat a set of objects equally without regard to implementation details. The classic distinction being the Is-A/has-A relationship.

Someone mentioned that they don't like the Cat/Dog run example b/c they would both use the same logic... however, I'd like to point out that is exactly a good reason to use polymorphism over interfaces...

Instead of Mammal, imagine the base class is Animal. Now, your animal class has a virtual function run, implemented in such a way that the majority of animals share this logic... now cat and dog inherit from animal and neither require any further run implementation because Animal already handles it. However, you also decide to create a bird Animal... it has a bird specific Run implementation (It actually flies so it's choice of path can ignore factors cats/dogs can't). Polymorphism is good here because all animals can "Run" in some sense of the word.

I would be willing to bet that the majority of AAA games use Polymorphism at least to some extent, but *in addition* they also make great use of composition. Composition is the has-a relationship where a behavior is attached to the object rather than derived from a base class.

If you look at unity3D, game objects are little more than an object to which behaviors can be attached, but those behaviors are derived from a base class, meaning each game object implements both composition and polymorphism to achieve the end result of being usable unit of code.

You might need polymorphism when you need to do the same operation to multiple types of objects.

However, polymorphism is not the only possible solution. You can go lower level and use something like function pointers instead (which might or might not come with lower overhead depending on implementation). You can also use external code to decide what should be done based on object type (eg. you could have a void* pointer associated with a type enum) using a switch or a pile of if statements.

Polymorphism is just syntax to simplify the usage of one of the above options, which hides some details and thus is more flexible in many cases. However, sometimes it makes sense to use one of the alternatives for performance reasons. This is because the compiler specific implementation of the virtual polymorphism "built in" to the language is likely to lack some of the knowledge you as a programmer have about the code, and thus will have to be general. Or perhaps the implementors decided not to cover every special case for simplicity and compilation speed or whatnot.

In other words, the built in polymorphism through virtual methods will always be able to handle the task, but more low level or specific approaches might be more desirable if you know your requirements.

o3o

Here are some good links:

So polymorphism is something like inverse operation in math. It does the opposite thing. In general you could create some object as you need them but with polymorphism you would create some group of object that would usually be represented with a single object. Than you would use base class (super class) as your primary class and do specific behavior trough inherited classes. Is this correct ?

Here are some good links:

So polymorphism is something like inverse operation in math. It does the opposite thing. In general you could create some object as you need them but with polymorphism you would create some group of object that would usually be represented with a single object. Than you would use base class (super class) as your primary class and do specific behavior trough inherited classes. Is this correct ?

Just think of it as a method that allows you to deal with multiple object types as if they were the one and the same. There are many methods that allow something like that, but the built in polymorphism with virtual classes and such is general and flexible, although more specific solutions might be better in a given situation.

o3o

Here are some good links:

So polymorphism is something like inverse operation in math. It does the opposite thing. In general you could create some object as you need them but with polymorphism you would create some group of object that would usually be represented with a single object. Than you would use base class (super class) as your primary class and do specific behavior trough inherited classes. Is this correct ?

Your basic description is roughly correct, but I think the way that you phrased it makes it sound confusing. In general, polymorphism through inheritance lets you interact with sub-class instances through the interface defined by the base class. Which methods of the base class are overridden in the sub-classes is not important to the user - they just want to refer to Mammals, and whatever the library creator overrode in each class is just an implementation detail.

This topic is closed to new replies.

Advertisement