Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (538)
Games in Android Showcase (132)
games submitted by our members
Games in WIP (600)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1] 2 3 4
  ignore  |  Print  
  Game Object Component System  (Read 26282 times)
0 Members and 1 Guest are viewing this topic.
Offline appel

JGO Wizard


Medals: 68
Projects: 4


I always win!


« Posted 2009-06-04 14:01:14 »

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.

Check out the 4K competition @ www.java4k.com
Check out GAMADU (my own site) @ http://gamadu.com/
Offline princec

« JGO Spiffy Duke »


Medals: 429
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #1 - Posted 2009-06-04 16:00:20 »

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

Cas Smiley

Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 840
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #2 - Posted 2009-06-04 16:26:12 »

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).

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline appel

JGO Wizard


Medals: 68
Projects: 4


I always win!


« Reply #3 - Posted 2009-06-04 16:35:58 »

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

Cas Smiley

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


I wonder if you could simulate multiple inheritance in Java.

Check out the 4K competition @ www.java4k.com
Check out GAMADU (my own site) @ http://gamadu.com/
Offline DzzD
« Reply #4 - Posted 2009-06-04 16:42:44 »


I wonder if you could simulate multiple inheritance in Java.
not really multiple inheritance but Interface may do the job

Offline appel

JGO Wizard


Medals: 68
Projects: 4


I always win!


« Reply #5 - Posted 2009-06-04 16:51:24 »

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?

Check out the 4K competition @ www.java4k.com
Check out GAMADU (my own site) @ http://gamadu.com/
Offline zammbi

JGO Coder


Medals: 4



« Reply #6 - Posted 2009-06-04 16:54:56 »

Quote
If only the Java language allowed multiple inheritance in some way out of the box it'd be great.
JavaFx  Roll Eyes

Current project - Rename and Sort
Offline cylab

JGO Ninja


Medals: 55



« Reply #7 - Posted 2009-06-04 16:58:34 »

Something like?:

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

1  
2  
3  
4  
5  
class HeavyTank implements Moving, Selecting, Shooting, ... {
    private Tank tank = new Tank();

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


Mathias - I Know What [you] Did Last Summer!
Offline DzzD
« Reply #8 - Posted 2009-06-04 17:04:46 »

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?

nop

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
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
1  
2  
3  
4  
5  
6  
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

Offline appel

JGO Wizard


Medals: 68
Projects: 4


I always win!


« Reply #9 - Posted 2009-06-04 17:11:06 »

1  
2  
3  
4  
5  
class HeavyTank implements Moving, Selecting, Shooting, ... {
    private Tank tank = new Tank();

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



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.

Check out the 4K competition @ www.java4k.com
Check out GAMADU (my own site) @ http://gamadu.com/
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline DzzD
« Reply #10 - Posted 2009-06-04 17:15:27 »

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.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
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 ?

Offline appel

JGO Wizard


Medals: 68
Projects: 4


I always win!


« Reply #11 - Posted 2009-06-04 17:23:16 »

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
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:
1  
2  
3  
GameObject tank = new GameObject();
tank.addComponent(new ShootingComponent());
((ShootingComponent)tank.getComponent("Shooting")).shoot();


Check out the 4K competition @ www.java4k.com
Check out GAMADU (my own site) @ http://gamadu.com/
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #12 - Posted 2009-06-04 17:31:02 »

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.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline DzzD
« Reply #13 - Posted 2009-06-04 17:33:31 »

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


what about:
1  
2  
3  
GameObject tank = new GameObject();
tank.addComponent(new ShootingComponent());
((ShootingComponent)tank.getComponent("Shooting")).shoot();


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

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

like

1  
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()

Offline princec

« JGO Spiffy Duke »


Medals: 429
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #14 - Posted 2009-06-04 17:36:40 »

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 Smiley

Offline cylab

JGO Ninja


Medals: 55



« Reply #15 - Posted 2009-06-04 17:59:40 »

what about:
1  
2  
3  
GameObject tank = new GameObject();
tank.addComponent(new ShootingComponent());
((ShootingComponent)tank.getComponent("Shooting")).shoot();


make that
1  
2  
3  
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


Mathias - I Know What [you] Did Last Summer!
Offline appel

JGO Wizard


Medals: 68
Projects: 4


I always win!


« Reply #16 - Posted 2009-06-04 18:14:07 »

make that
1  
2  
3  
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:
1  
2  
3  
4  
5  
6  
7  
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?



Check out the 4K competition @ www.java4k.com
Check out GAMADU (my own site) @ http://gamadu.com/
Offline DzzD
« Reply #17 - Posted 2009-06-04 18:18:05 »

what about :

1  
getComponent(String s) throws UnavailableComponentException



Offline cylab

JGO Ninja


Medals: 55



« Reply #18 - Posted 2009-06-04 18:37:15 »

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

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.


Why not:
1  
2  
3  
4  
5  
GameObject tank = new GameObject("Tank Unit");

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


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.

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


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:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
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...

Mathias - I Know What [you] Did Last Summer!
Offline appel

JGO Wizard


Medals: 68
Projects: 4


I always win!


« Reply #19 - Posted 2009-06-04 18:51:00 »

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.

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()
}

Check out the 4K competition @ www.java4k.com
Check out GAMADU (my own site) @ http://gamadu.com/
Offline Niwak

Senior Devvie


Medals: 1
Projects: 1



« Reply #20 - Posted 2009-06-04 18:59:07 »

Reading your post, I think that maybe the adapter design pattern could be exactly what you need.

The usual implementation for this pattern is to have a factory in charge for creating adapters for objects.
It gives you something like this ;

1  
2  
3  
4  
5  
6  
7  
8  
ComponentInterface componentInterface = componentFactory.adapt(gameObject, ComponentInterface.class)

For your example, it gives :
Shooting shooting = shootingFactory.adapt(entity, Shooting.class);
if (shooting == null) {
  // entity is not able to shoot so skip
} else {
}


An easy way to implement all this is to use a simple modeling framework like Eclipse's EMF. it seems to not be that much in the habits of game developpers but I still find it very usefull and efficient since it will provide you with the code for adapting objects as well with a notifier system for keeping your adapters up to date (which is way trickier and error prone).

    Vincent
Offline princec

« JGO Spiffy Duke »


Medals: 429
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #21 - Posted 2009-06-04 19:06:53 »

Everyone's problem here is that you are attempting to expose the behaviour of the Tank (or whatever) by adding interfaces to say what it can do. However its public interface should be only what is required for it to interact with its world. Typically that'll be quite a brief selection of methods, like init(), think(), damage().

The shooting and moving stuff - that's basically private stuff. By all means break that code out into specialist classes that take private implementations of, say, a Moveable or Armed interface - but don't expose these at the top level. For example:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
interface Weapon {
   void fire();
}

interface Movement {
   void move(Moveable m);
}

interface Moveable {

   void setLocation(float x, float y);
   float getX();
   float getY();
}

abstract class Entity {

   abstract void tick();

}

class Tank extends Entity {

   float xPos, yPos;
   
   Moveable moveable = new Moveable() {
      void setLocation(float x, float y) {
         xPos = x;
         yPos = y;
      }
      float getX() {
         return xPos;
      }
      float getY() {
         return yPos;
      }
   });
   Movement movement = new SpecialTankMovementRoutine();
   Weapon cannon = new Cannon();
   
   void tick() {
      movement.move(moveable);
      cannon.fire();
   }
}

A bit of a manufactured example but not too far off what I'm getting at. Just try to keep the public interfaces of the classes restricted to that which is needed to communicate with as few other classes as possible.

All kinda pointless in the grand scheme of things. You're writing a game. Just make it work.

Cas Smiley

Offline cylab

JGO Ninja


Medals: 55



« Reply #22 - Posted 2009-06-04 19:35:51 »

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()
}

Isn't that exactly what I said!?  Cool

Mathias - I Know What [you] Did Last Summer!
Offline appel

JGO Wizard


Medals: 68
Projects: 4


I always win!


« Reply #23 - Posted 2009-06-04 20:34:36 »

Everyone's problem here is that you are attempting to expose the behaviour of the Tank (or whatever) by adding interfaces to say what it can do. However its public interface should be only what is required for it to interact with its world. Typically that'll be quite a brief selection of methods, like init(), think(), damage().

The shooting and moving stuff - that's basically private stuff. By all means break that code out into specialist classes that take private implementations of, say, a Moveable or Armed interface - but don't expose these at the top level.

You're absolutely right!

However, I'm not trying to expose a component to the "outside world", but rather expose their interface to each other.

E.g., SelectComponent needs to be able to look up the VisualsComponent within the same gameobject in order to render a selection rectangle of the correct size around the selected game object.

All GameObject instances contain a list of component instances for that object, and all components have a reference to it's gameObject owner. That way they can look up other components within the same gameObject, e.g. owner.getComponent("Visuals"), and communicate with it.

You might have a MovementComponent called SlowWhenDamagedMovementComponent, which has a dependency on HealthComponent, which has a public method "getHealth()". You get the idea.

All gameObjects reside in some gameObjects collection, which gets iterated, e.g.:

for(GameObject gameObject : gameObjects)
  gameObject.update(delta);

and

for(GameObject gameObject : gameObjects)
  gameObject.render(g);


The gameObject instance would then iterate all it's components and perform the same update() and render() on it's components.

That's just about the only communication to the outside world, in theory. Otherwise they manage themselves independently.

Check out the 4K competition @ www.java4k.com
Check out GAMADU (my own site) @ http://gamadu.com/
Offline princec

« JGO Spiffy Duke »


Medals: 429
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #24 - Posted 2009-06-04 22:43:21 »

It all sounds, er, overcomplicated. Games, when you get right down to the fiddly stuff, really aren't very complex, unless you overcomplexify them yourself.

Cas Smiley

Offline appel

JGO Wizard


Medals: 68
Projects: 4


I always win!


« Reply #25 - Posted 2009-06-04 22:52:49 »

It all sounds, er, overcomplicated. Games, when you get right down to the fiddly stuff, really aren't very complex, unless you overcomplexify them yourself.

Cas Smiley

Unless you're making a RTS game that has FOUR races, and each race having something like 8 unit types, it helps having reusable components, and defining these guys in an external data file.

Check out the 4K competition @ www.java4k.com
Check out GAMADU (my own site) @ http://gamadu.com/
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #26 - Posted 2009-06-05 00:42:58 »

This is an interesting conversation.

Why not include a scripting language and then you can just have each unit implement multiple scripts to define their behavior?  Tongue

See my work:
OTC Software
Offline princec

« JGO Spiffy Duke »


Medals: 429
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #27 - Posted 2009-06-05 01:04:22 »

See, I'd see that simply as 32 classes. Not exactly a lot of complexity. I expect that the inheritance heirarchy would be pretty simple too.

Cas Smiley

Offline ewjordan

Junior Devvie





« Reply #28 - Posted 2009-06-05 01:25:34 »

For the topics under discussion currently, I'd just use Scala traits.  Scala cross compiles with Java with no problem, and after Proguard cuts the Scala libs down you're only adding a few kb to your game size anyways.

What is this "Game Object Component System" thing, though?  Is that just fancy language for the properties pattern, or is there something else going on there?  Anyone care to give a paragraph summary of what we're discussing here?
Offline appel

JGO Wizard


Medals: 68
Projects: 4


I always win!


« Reply #29 - Posted 2009-06-05 11:02:04 »

What is this "Game Object Component System" thing, though?  Is that just fancy language for the properties pattern, or is there something else going on there?  Anyone care to give a paragraph summary of what we're discussing here?

Basically, instead of having a concrete entity class that extends other classes to inherit their functionality, you rather have multiple components for each independent functionality (like movement, shooting, visuals, selecting, etc.). Those components are then binded together in a gameobject/entity container class, that does nothing but to contain the components of that certain gameobject.


This is a nice enough article:

Evolve Your Hierarchy 
http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/


Check out the 4K competition @ www.java4k.com
Check out GAMADU (my own site) @ http://gamadu.com/
Pages: [1] 2 3 4
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

rwatson462 (29 views)
2014-12-15 09:26:44

Mr.CodeIt (20 views)
2014-12-14 19:50:38

BurntPizza (40 views)
2014-12-09 22:41:13

BurntPizza (75 views)
2014-12-08 04:46:31

JscottyBieshaar (37 views)
2014-12-05 12:39:02

SHC (50 views)
2014-12-03 16:27:13

CopyableCougar4 (47 views)
2014-11-29 21:32:03

toopeicgaming1999 (113 views)
2014-11-26 15:22:04

toopeicgaming1999 (100 views)
2014-11-26 15:20:36

toopeicgaming1999 (30 views)
2014-11-26 15:20:08
Resources for WIP games
by kpars
2014-12-18 10:26:14

Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!