Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411276 Posts in 69323 Topics- by 58380 Members - Latest Member: bob1029

March 28, 2024, 11:09:58 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Component-Based Architechture: Getting Away from Inheritance
Pages: 1 2 [3] 4
Print
Author Topic: Component-Based Architechture: Getting Away from Inheritance  (Read 36990 times)
Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #40 on: January 11, 2010, 05:24:34 PM »

It would have been nice if you had said something more qualified, such as "That's true, it can be nuts.  I get around that by using GDB, and making sure I never sign up to work in multiple languages unless I have access to an IDE and language that GDB supports.  YMMV, however, because I realize that not everyone can guarantee that."

I don't use an IDE, just vim and a makefile.  I run GDB from a command line, and never run into any issues, and I do a lot of mixed language programming (generally Ada + some C variant).  Perhaps the IDE interfaces to GDB are what cause the complications.

Quote
As for your second point, you say, "Yes, I absolutely would, assuming a suitable compiler existed."  That is an asinine assumption to make in light of the context of the poster's question.  Such a compiler does not exist, and we are all well aware of that.

I was not aware of that.  I don't do anything with Flash, but I swear somebody wrote a GCC backend for Flash at some point.  Maybe I'm misremembering.

Quote
The original poster's question was rhetorical, and was intended to point out that he does not have access to such a compiler.

I didn't read it as rhetorical.

Quote
If he did, I don't think he wouldn't have said what he said in the first place.

I drew the exact opposite conclusion, the ambiguity of the written word strikes again!

Quote
I believe that his very point was that Objective C locks you into platforms that support Objective C.

GCC compiles Objective C, and GCC is the most widely ported compiler suite in existence.  I would hardly think you could call that "lock in."

The point is not Objective C anyway, the point is choosing combinations of languages based on what works best.  I believe Obj-C is a superior and easier solution to this particular problem.  The same goes for other areas.  If I were writing a game that needed high-performance math, I would do those sections in Fortran, etc...
Logged



What would John Carmack do?
westquote
Level 0
**


I make games in Philly. How rare!


View Profile WWW
« Reply #41 on: January 11, 2010, 06:04:57 PM »

Ah, my apologies, it seems there was some mis-communication.


GCC compiles Objective C, and GCC is the most widely ported compiler suite in existence.  I would hardly think you could call that "lock in."


I agree that GCC may be portable enough for many or most peoples' needs, but what I was mentioning above about DS, Wii, and 360 development, as well as Flash (since I am not aware of such a port) is exactly what I would call "lock in".  Choosing to develop in Objective C locks you into developing in situations where you have access to an acceptable compiler.  Saying that it's not is akin to saying that because DirectX runs on the majority of computers, choosing to write non-portable code that uses it doesn't lock you into developing for platforms that support DirectX.  It does; the question is whether this constraint affects you at all.  I'm guessing that in your case it doesn't, and that's fair enough.


GCC compiles Objective C, and GCC is the most widely ported compiler suite in existence.  I would hardly think you could call that "lock in."

The point is not Objective C anyway, the point is choosing combinations of languages based on what works best.  I believe Obj-C is a superior and easier solution to this particular problem.  The same goes for other areas.  If I were writing a game that needed high-performance math, I would do those sections in Fortran, etc...


Agreed, this is a good point.  I have found the combination of C++ and Lua to be incredibly expressive and productive.  Having a systems language and an extension language is now a requisite part of any development environment I set up.

The point that I was making is that it is often not easy to use/debug an auxiliary language, depending on which language you are trying to use, and what environment you are trying to use it in.  Such flexibility in your choice of language comes at the cost of very real constraints that, for various reasons, not everyone has the luxury of disregarding.
Logged

Twitter: @westquote - Webpage: Final Form Games
synapse
Level 1
*



View Profile
« Reply #42 on: January 12, 2010, 12:28:47 PM »

I guess my point is that platform comes before paradigm.  Choosing your target audience is a helluva lot more important than choosing which language will do what you want without an additional hour or two of programming.
Logged
rboarman
TIGBaby
*


View Profile
« Reply #43 on: January 19, 2010, 10:46:26 AM »

Has anyone got any thoughts on how to persist and load a series of component based objects in an efficient manner?

I'm looking at using C#'s serialization but it seems too inefficient for a large number of objects (>500,000).

Any ideas?

Rick
Logged
raigan
Level 5
*****


View Profile
« Reply #44 on: January 19, 2010, 07:44:37 PM »

500k objects?!?
Logged
jotapeh
Level 10
*****


View Profile
« Reply #45 on: January 20, 2010, 05:08:00 PM »

I'd just like to say I really appreciate the OP.

I'm not sure if it's 100% how I'd like to do things, but it's very nice to have this approach explained in such a clear manner. I'll definitely be trying to figure out how to use the strengths of this approach in my projects.

Cheers and thanks for a good write-up.  Beer!
Logged
Mikademus
Level 10
*****


The Magical Owl


View Profile
« Reply #46 on: January 23, 2010, 05:08:06 AM »

Summing up the problem: You want (1) flexibility enough to compose the behaviour of your entities, while not incurring (2) run-time overhead or code maintenance problems. Using inheritance or multiple inheritance will be efficient runtime-wise but scale poorly. Using a component architecture will in a large-scale application with a rich set of components and densly combined entities scale nicely but be increasingly expensive, eventually prohibitively so.

In a sophisticated C++ design this is a non-issue. If you accept defining your behaviour in code (as opposed to external scripts) you can have the full flexibility of components with no runtime overhead if you use policy-based templates, as per A. Alexandrescu (2009). As with all templates this may increase compilation times.

So we want flexibility about movement, attacking and interactions, or whatnot. Say we define an entity as

Code:
template<typename MOVE, typename ATT, typename INTER>
class Entity : public MOVE, public ATT, public INTER
{
   ...
};

You can specify any number of policy classes and combine these to your hearts' content:

Code:
struct SessilePolicy
{
    void move(double deltat) {}
};

struct MovePolicy
{
    void move(double deltat) { RunSomewhere(); }
};

struct PacifistPolicy
{
    void attack() {}
};

struct PsychoPolicy
{
    void attack() { GoBeserk(); }
};

struct ShootLaserFromEyesPolicy
{
    void attack() { EatThis(); }
};

struct NoninteractablePolicy
{
   void interact() {}
};

struct ChattyPolicy
{
   void interact() { Eliza(); }
};

Now you can compose your game entities

Code:
typedef Entity<SessilePolicy, PacifistPolicy, NoninteractablePolicy> DummyEntity;
typedef Entity<MovePolicy, PsychoPolicy, NonteractablePolicy> GenericEnemy;
typedef Enity<MovePolicy, ShootLaserFromEyes, ChattyPolicy> ExampleFromPreviousPost;

ExampleFromPreviousPost myWeirdHouse;

In short, we live in a richer world of architecture than just having to choose between inheritance or components. Not many people code in Smalltalk nowadays, but this language separates inheritance of types from inheritance of implementation, and just as Objective-C uses signalling to communicate. Less frequently used languages, but a fourth architectural option.

Template composition of policy classes is one way to achieve the same results as components but without sacrificing runtime efficiency or code manageability, while retaining the full type-safety and debugging tools of C++, which you wouldn't have in scripting.
Logged

\\\"There\\\'s a tendency among the press to attribute the creation of a game to a single person,\\\" says Warren Spector, creator of Thief and Deus Ex. --IGN<br />My compilation of game engines for indies
BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #47 on: January 23, 2010, 05:36:39 AM »

Multiple inheritance like that is not ideal either. It is not what policies were designed for. The way you've designed it, there's no root Entity class, which makes it basically useless for games (unless you go even further down the template path). Nor is there any dispatching or interfaces, so that at runtime I can call the correct move method.
You can fix these problems without much fuss with virtual inheritance, but then it starts to resemble component architecture much more than I think you were intending.
Logged
Mikademus
Level 10
*****


The Magical Owl


View Profile
« Reply #48 on: January 23, 2010, 07:45:55 AM »

Multiple inheritance like that is not ideal either. It is not what policies were designed for.

Hmm? That's exactly what policies were designed for. Ok, let's define it a little bit more clearly:

Code:
struct Entity
{
    virtual void move() =0 {}
    virtual void attack() =0 {}
    virtual ~Entity() {}
};


template<typename MOVE = DefaultMovePolicy, typename ATTACK = DefaultAttackPolicy>
struct ComposedEntity : public Entity, public MOVE, public ATTACK
{
    void move() { MOVE.move(); }
    void attack() { ATTACK.attack(); }
};

What we have here is a class ComposedEntity that fulfil the Entity interface and can thus be used polymorhpically. Since you will use it polymorhpically you've already accepted that all principal methods must be declared in an interface as well as paying the slight overhead of a vftable (which however is much less an overhead than an extensive component architecture will incur).

The class will fulfil the Entity interface. It will always have the required methods. All without "having gone further down the template path" (which you make is sound like a bad thing, btw? Templates used judiciously--as any language facility should be used!--are a boon for games development) or using virtual inheritance, which is a tool for resolving the diamond of inheritance, and how that would resemble components is an obtuse claim...
Logged

\\\"There\\\'s a tendency among the press to attribute the creation of a game to a single person,\\\" says Warren Spector, creator of Thief and Deus Ex. --IGN<br />My compilation of game engines for indies
Klaim
Level 10
*****



View Profile WWW
« Reply #49 on: January 23, 2010, 01:27:43 PM »

In the current C++, you have no way to specify an undefined number of types.

Using policy is not as flexible as using components because you cannot easily add components. Components have to be orthogonal "aspects" of the same object. Sometimes they are interdependant but it's component-relative, not object-relative.

So using policy here is almost the same as using multiple inheritance. You get the interface exposure but you cant easily make changes to code.

Anyway, using policy is just about choosing polycy of behaviour, not "aspects" of the objects. I'm not sure I'm clear here...
Logged

BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #50 on: January 23, 2010, 04:15:03 PM »

Well now you've changed what you are doing. In the first example, I thought you were inheriting Entity::move from MOVE. Now you are not. In fact, you are not really using any features of inheritance once you've done that, you might as well have written:
Code:
template<typename MOVE = DefaultMovePolicy, typename ATTACK = DefaultAttackPolicy>
struct ComposedEntity : public Entity
{
    MOVE move;
    ATTACK attack;
    void move() { move.move(); }
    void attack() { attack.attack(); }
};
no?

Also, Klaim makes some good points.

Anyway, don't get me wrong, I love templates. They can just explode in complexity if you think you can recreate every runtime feature at compile time.

In my mind, virtual inheritance is creating multiple subobjects, and linking them together with pointers (as opposed to laying them out in fixed relation to each other in memory with regular inheritance). Certainly seems like components to me.
Logged
Mikademus
Level 10
*****


The Magical Owl


View Profile
« Reply #51 on: January 24, 2010, 05:34:50 AM »

Ok, I'll admit I designed my example poorly and thus didn't make a very good case for policies. And as given, you can rewrite my source as you did. However, when writing policies each policy class generally also implements an interface, and one thing you can't do when rewriting like you did is iterating over a set as instances of those policy interfaces. However, if you take this to its full extent, where classes don't need to have all policies, you will need to test for their existence dynamically and you will have created a statically defined component model with some run-time testing overhead.

Nonetheless, I should have given a better example. Still, mutatis mutandis the architecture I suggested, and *proper* policies Wink, is a good compile-time alternative to a dynamically composed component architecture. If the examples above look quite like components, then that is probably because they really are quite similar, the difference being that the templated version (if well designed) will not entail run-time tests.
Logged

\\\"There\\\'s a tendency among the press to attribute the creation of a game to a single person,\\\" says Warren Spector, creator of Thief and Deus Ex. --IGN<br />My compilation of game engines for indies
Klaim
Level 10
*****



View Profile WWW
« Reply #52 on: January 24, 2010, 06:11:20 AM »

Once C++0x is here and usable, we can use templates to statically setup components by using template variants.
Logged

powly
Level 4
****



View Profile WWW
« Reply #53 on: January 24, 2010, 06:55:07 AM »

Once C++0x is here and usable, we can use templates to statically setup components by using template variants.

C++1x, you mean ;>

But all this discussion seems kind of confusing to me, I'm just using classes to represent things and sometimes things inside things.. I've never had an actual need to inherit, not to mention use some component stuff.
Logged
Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #54 on: January 24, 2010, 10:22:33 AM »

Once C++0x is here and usable, we can use templates to statically setup components by using template variants.

Do you mean variadic templates?  I've been following C++0x very closely, and have never seen "template variants."

This:
Code:
template <typename... Components>

The possibilities offered by these babies are staggering.  GCC has them now, if you want to play.
Logged



What would John Carmack do?
Klaim
Level 10
*****



View Profile WWW
« Reply #55 on: January 24, 2010, 10:31:17 AM »

That occurs only in some kind of systems where you need some objects to have common base class because they are all under the same "laws" of the game. Often all the movable objects in a game share a common base.

Now the idea is that instead of using inheritance that creates a strong relationship between classes, you simply "compose" your game object types with "aspect/behaviours" that are components.

That's easy when you just compose a class the usual way:
Code:
class Player
{

  GraphicEntity m_gfx;
  PhysicEntity m_physic;
  LivingEntity m_lifestate;
};
So now the problem is more about "exposing" the components to the "surface" of the type, allowing external system to manipulate specific aspects of the instance of this type.
In fact, in C++ it's hard to expose interface without inheritance, so it seems better at first glance. But it's a bad solution as stated before.

In ActionScript3 you can do this without inheritance, because reflection allow you to "scan" the members of the object, so a simple naming rule for components could be enough.

In C++ however you'll need something as exposed in the first message to allow the system to access the components dynamically with a clear interface to the world.

Now I say that because I used a similar system in an aborted project long time ago and I see the benefits. But the game I'm working on today don't need at all this system. It's not always appriopriate. It is when you have to separate different aspects/behaviour from the entity type. If you already know that there is no way a door can speak in your game and your class hierarchy is fixed or there is no class hierarchy, you shouldn't bother. It's just a good technic to know when you're making a systemic game world. Almost any RPG is.

Quote
Do you mean variadic templates?  I've been following C++0x very closely, and have never seen "template variants."

Ah yes sorry it was late when I posted, "variadic templates" are what I was thinking about.
Logged

jotapeh
Level 10
*****


View Profile
« Reply #56 on: January 24, 2010, 06:34:04 PM »

In ActionScript3 you can do this without inheritance, because reflection allow you to "scan" the members of the object, so a simple naming rule for components could be enough.

Can you expound upon this further? I'm not understand quite what you mean by "Reflection". Please help a hopelessly oblivious fellow  Who, Me?
Logged
zantifon
Level 0
**


View Profile WWW
« Reply #57 on: January 24, 2010, 11:57:15 PM »

Reflection is the ability of a programming language to inspect and modify it's own behavior. In this case, he is referring to the ability to query the type of an object at runtime. So you could store the components as a basic list of objects. Then, at runtime, iterate over then and get the name of the type as a string and do logic based on what the string is. Many languages (including AS3) have reflection, but C++ does not (well, it does, sort of, but it's not as useful and largely not cross-platform). This strategy would work with any language with reflection.


I have to say though, I think keeping components in a list is a bad idea to begin with. In my designs I don't even have an Entity class at all. Entities are simply identifiers (like an int or something). Then for each component type, you have a map from entities to components. Entities are defined simply by whichever component maps have entries for that entity. It's almost like a relational database.

Then you don't need to do any kind of reflection or any other RTTI or template hacks or whatever. If you want to get the component for a particular entity, query the map. If it doesn't have one it won't be in the map. If you want to iterate over all components to do logic, just iterate over all the maps. You'll process things in a different order, but I've found this to actually be easier to work with then processing one entity at a time.
« Last Edit: January 25, 2010, 12:20:24 AM by zantifon » Logged
Klaim
Level 10
*****



View Profile WWW
« Reply #58 on: September 24, 2010, 08:21:13 AM »

(sorry for the necromancing but it seems important)

I just hit this question/answer that got me to this blog post that is really interesting on the subject of Component-Based Architecture. Leads also to Functional-Reactive Architecture that I didn't heard about before!

Thought people here will be interested.
Logged

rogerlevy
Guest
« Reply #59 on: September 26, 2010, 05:37:05 PM »

My game engine uses a component-based architecture.  I think I'm going to be reading this thread throughout the coming week.  I want to see if I can get more smarts on the topic Tongue
Logged
Pages: 1 2 [3] 4
Print
Jump to:  

Theme orange-lt created by panic