5
\$\begingroup\$

I am working on a 3D game, and need some advice about how to best design and structure my code so that I achieve what I'm going for without using bad practices like multiple inheritance.

Basically I keep finding myself tempted to implement multiple inheritance with simple interfaces.

For example, I have an abstract base class, Physical_Object, and I have an abstract class derived from it, Controllable, and I have a class derived from Controllable, Drone.

Controllable must implement an update method, which, depending on the state of the controllable, will either call an AI update method, or an update method based on the keyboard/controller state.

A Drone has different segments, of which are interchangeable, and have different abilities.

Some of these segments, as well as some other future game objects will need to be able to target/trace a ray from their origin to where they are aiming. So I thought to make a new abstract class / interface which requires the implementation of target.

Currently, I have an abstract Drone_Segment class, which helps to allow me to polymorphically manage the Drones interchangeable segments. And these each have hierarchies, like for example, Drone_Turret_Segment: Physical_Object-->Controllable-->Drone_Segment->Drone_Turret_Segment.

In essence, given the current structure and design, the quickest and easiest way to add the target method to all of the classes which will need it, without multiple inheritance, is to add and implement target in the Controllable class. But this would have the downside, that Objects that have no logical use for the method would inherit it.

Another option is to make a simple interface and make just objects which need the target method inherit from it, but I cannot figure out how to best do this without multiple inheritance, ie: Physical_Object-->Controllable-->(Drone_Segment,Targeting_Object)->Drone_Turret_Segment.

What are some ways to go about this?

\$\endgroup\$
  • \$\begingroup\$ How separated are these parts of an object? Is it possible to just add a "controllable" to an object that has access to things like the object's position? \$\endgroup\$ – PixelArtDragon Aug 6 '13 at 3:50
  • \$\begingroup\$ @Garan: Yes. A physical component of another game object will have either a pointer to the object that contains it, or an id that maps to it. \$\endgroup\$ – MVTC Aug 6 '13 at 4:02
9
\$\begingroup\$

Note that there is nothing wrong with multiple inheritance. The diamond inheritance issue is... a problem. Plain multiple inheritance with no common bases is quite useful.

That said, inheritance at all is generally the wrong approach unless you're implementing functional interfaces. Many class hierarchies, including your own, end up looking too much like real-world taxonomies.

Consider aggregation/composition over inheritance. Instead of thinking "a Drone is-a Controllable in behavior" think instead "a Drone has Controllable behavior."

You can do static aggregation or dynamic composition. The latter has a lot of advantages, but the former is quite fine.

The usual article to link with a better-worded explanation is Evolve Your Hierarchy.

\$\endgroup\$
  • \$\begingroup\$ You beat me to it :( \$\endgroup\$ – RandyGaul Aug 6 '13 at 5:35
3
\$\begingroup\$

Dependency Injection is able to solve this problem.

A top-level object, rather than implementing or overriding a specific process, defines that it requires an object capable of fulfilling it. It also defines what that object is supposed to do, i.e. it defines the component's interface. Then smaller, simpler, and independently implemented objects must fulfill that interface. This is backwards from classic polymorphism, where low-level objects define and high-level objects implement, hence the name Dependency Inversion Principle.

For instance, your Drones can require an object that implements Update() and do their updating via that property. That object is independent of the inheritance chain. The object fulling the interface can work by an AI process, or it could sample player input, or it could follow a script, etc. No code duplication because each implementation is exactly what it needs and no more, but also no unnecessary inheritance in child classes. No multiple inheritance, either.

Note that this architecture's goals are roughly the same as this site's ever-popular Component-Entity architecture. The idea is to remove functional parts from object definitions, make functions modular, and improve the brittle programs created by using inheritance directly.

\$\endgroup\$
  • \$\begingroup\$ Geez, let some other folks chime in. :) This question deserves more than one answer. \$\endgroup\$ – Seth Battin Aug 6 '13 at 4:45
1
\$\begingroup\$

It really sounds to me like you want to use multiple inheritance to mix together different pockets of functionality to form something new. While dependency injection can be useful in an inheritance hierarchy, a better option would be to form aggregate object compositions.

Using a component based architecture is a simple and natural way to piece together different types of game objects. What you're really doing, on a fundamental level, is creating new things from pre-existing implementations. This is what component based architecture is for: you create objects based off of what they do, instead of using inheritance hierarchies that organize implementation and code based off of abstract naming identifiers.

A component based architecture will allow you to avoid the age old problem of features creeping up your inheritance hierarchy in order to avoid code duplication.

\$\endgroup\$
1
\$\begingroup\$

I would look into component design

http://gameprogrammingpatterns.com/component.html http://www.gamasutra.com/blogs/MeganFox/20101208/88590/Game_Engines_101_The_EntityComponent_Model.php

It uses wrapper classes and loads them with reusable components. This has several advantages. First is "flattens" out an inheritance tree. Say you have a vehicle superclass with two sub classes: Tires and Treads. Tanks then a sublcass of Treads. But what if you want a tank with tires? Do you inherit from tanks to reuse the gun logic, or do you inherit for tires to get the wheel logic. Or do you inherit from both and get the dreaded diamond? With component design you can have a general vehicle class and then components. Propulsion can be one type of components, (sublcassed into tires, wheels, propellers, or wings) and gun can be another type of component. Essentially, component systems are useful if you have a wide array of objects that reuse functionality, but not necessarily inherit from each other.

There are other advantages also. Like you can store all of the same type of components next to each other in memory and update one type of component at a time. You will spend less time pulling random components then, but only worry about this if you need to improve performance.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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