Game Object Component System

I’d like to open a discussion thread about a Game Object Component System, aka. Component Based Entity System.

There isn’t much discussion about this.

I’ve recently adopted this technique from Game Programming Gems 6, and I find it’s far superior to the old inheritance way. The headache of deciding if MovementEntity should inherit from ShootingEntity or the opposite is gone.

As I continue to use this technique the questions accumulate. These are mostly trivial questions, design and architecture questions, and also some fundamental questions, e.g. what should the game object know, component dependencies, etc.

Hopefully some masters of this technique can come forth and explain their way of using it.

If only the Java language allowed multiple inheritance in some way out of the box it’d be great.

Cas :slight_smile:

AFAIK “Game Object Component System” is also used in C++, to get around the many problems with C++ multiple inheritance in this context (game objects).

How would you create a data-driven gameobject system in a multiple-inheritance language?

I wonder if you could simulate multiple inheritance in Java.

not really multiple inheritance but Interface may do the job

Something like?:

class Tank implements Moving, Selecting, Shooting, … {

… implement all functionality here…

}

But what do you do when you need to create a HeavyTank unit? Implement all the same code?

[quote]If only the Java language allowed multiple inheritance in some way out of the box it’d be great.
[/quote]
JavaFx ::slight_smile:


class HeavyTank implements Moving, Selecting, Shooting, ... {
    private Tank tank = new Tank();

... delegate functionality to "tank" here... 
}

nop


class Tank implements Moving, Selecting, Shooting, SpecialProperties... 
{
... implement all functionality here 

or use inner class Selector/Shooter/Mover... 

}

Tank t=new Tank();
t.getSelector().selectMe()
t.getMover().moveBy(1,1)
t.getMover().moveTo(50,50)
t.getSpecialProperties().isHeavy()
t.getSpecialProperties().isColored()


or


class HeavyTank extends Tank  {
... implement all functionality here 

or use inner class Selector/Shooter/Mover... 

}

but it is still a tank so that’s right

EDIT: removed implements on HeavyTank extends Tank

What about distinctive game objects such as a Tank and a Defense Tower? Both require the Shooting and Selecting ability, but not Moving. Or Helicopter and Soldier, Dog and Rocket.

This method has an inheritance “stink” in my opinion.

A component based system allows you to define new entity types in a data file, XML. That is a big plus. Then you only have a set of specialized components that may or may not interact, and then you can define all the more concrete classes of entities in a XML file.


class Shooter
class TankShooter extends Shooter
class TowerShooter extends Shooter


class Tank implements Moving, Selecting, Shooting
class Tower implements Selecting, Shooting

tank.getShooter().shoot()
tower.getShooter().shoot()

no ?

That’s what I meant by inheritance stink. You’re actually going into components here, specializing functionality in a Shooter “component” class.

what about:

GameObject tank = new GameObject();
tank.addComponent(new ShootingComponent());
((ShootingComponent)tank.getComponent("Shooting")).shoot();

So I think I chatted to appel about this in irc, but I’ve been interested in trying a component-based design for a while. Rescue Squad gets away with doing things in a very simple way (lots of interfaces like cylab’s example), which works but leads to quite a bit of tedious boilerplate and duplication.

When/if I move on and do RS3 I’ve got ideas for a much more complex simulation with lots of different vehicles and props the interface-heavy approach just isn’t going to scale and component-based looks like being a good alternative.

In some ways this reminds me of behaviour trees, in that you end up writing small chunks of functionality (walk_to, search_area) and then using an xml structure to plug them together. Individually the components are stupid/simple, it’s only when assembled that they become bigger than the sum of their parts.

With behaviour trees I had similar problems when components had to interact. I ended up with a certain amount of instanceof and some annoying implicit dependencies (like certain behaviours expected to be next to another type of behaviour). I’m still not certain how this is best solved.

I was just trying to answer about a way simulating multiple inheritance

this looks nice and seems to be a very generic way.

thats basically enable adding/removing interface at runtime, no ?

like

tank.addComponent(new ShootingComponent());

could means that this tank implements Shooting and is a “shooting tank” not a “simple tank”, this looks nice

EDIT:
but in another way interface enable you to keep a collection/list of object shooter that are differents (tank/soldier/tower) and act the same way on them in a loop like

for every IShooter in myShooterList
shooter.shoot()

You’re just trying to get around inherent deficiencies in the Java language here. It just doesn’t have the constructs to do what you want in a nice elegant way. Mostly you’ll end up with a ton of boilerplate code (delegating interface methods to concrete instances inside some class), a bunch of instanceofs because there’s no dynamic class creation easily made, or something that can’t be reliably checked at compile time for sense. Bah.

Cas :slight_smile:

make that


GameObject tank = new GameObject();
tank.addComponent(new TankShooter());
tank.getComponent(Shooter.class).shoot();

You should provide empty default-implementations in GameObject() for common components, so you won’t get an NPE all the time :wink:

Why do you need the concrete TankShooter class? It implies you have a Tank unit in your game.

Why not:


GameObject tank = new GameObject("Tank Unit");

ShootingComponent shootingComp = new ShootingComponent();
shootingComp.setShootingInterval(500); // every 500 ms.
tank.addComponent(shootingComp);

tank.getComponent(ShootingComponent.class).shoot(); // You mean NPE here?

what about :

getComponent(String s) throws UnavailableComponentException

The TankShooter was just an example. I think you should use an interface as component specification, so you can implement a component different if needed. Nothing stops you from providing a default implementation that covers 90% of the cases. But an interface is mandatory in my opinion.

That would be a good example for a default implementation, but setShootingInterval() should not be part of the Shooter interface, since you may want to implement a shooter with random or accellerating shooting interval.

Yep. Providing a default implementation (maybe logging a warning like “A Shooter was requested on a pacific GameObject”) in this case would prevent a NPE.

But thinking about this a bit more, you would rather want a container that returns the available components for containing gameobjects:


GameObject gameobject1 = (...)
GameObject gameobject2 = (...)
(...)
GameObject gameobjectN = (...)

GameObjectContainer container = new GameObjectContainer();
container.add(gameobject1);
container.add(gameobject2);
(...)
container.add(gameobjectN);

// Returns a list with Shooter components for the contained GameObjects if available
List<Shooter> shooters = container.filter(Shooter.class);

// now shoot along...

You could do a

interface Shooting {
void shoot();
}

class IntervalShootingComponent implements Shooting {

public void setInterval(int ms);
}

class RandomIntervalShootingComponent extends IntervalShootingComponent {
public void setIntervalMinMaxOffset(int ms);
// and override shoot()
}