Public Group

# Replacing ECS with component based architecture, or traditional OOP, or something else?

This topic is 1004 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I am asking this question purely out of interest, and hopefully you guys can point some interesting links my way. I am a relatively new C++ programmer. I feel I have the basics down pact, but it is actually putting them all together in a software project that I find very very very very hard.

So I am making a 2d space ship game and came across ECS via this forum. I was intrigued by the concept and ended up using entitiyX in my game. The game is quite simple now (just the player ship, and some enemy ships that shoot at the player) and I am still learning how to properly use entityX to achieve my goals.

To be honest I am now coming to think of ECS as almost a 'convenience game API' for noobs like me that want to do all the stuff a game should do, but can't program it. For example I made it so my spaceship could shoot a spell, a fireball. To do this I created a SpellSpawner component (the invisible 'thing' I assign to entities that can shoot spells), a Spell component (the actual spell that is created), and the SpellSpawner System (the system which implements the spell logic). The main bit of the logic reads

for (entityx::Entity entity : entities.entities_with_components(position, spell))

which allows me to use those entities that have position and spell components,I then create the fireball entity with

SpellCreator(entity.id(), initVelocity, spellPosition.position, spellPosition.heading, spell->spellType, Colors::Orange).create(entities.create(), nullptr);

which creates my spell entity, and the spell 'moves' because it has components motion and position,and is picked up by the MovementSystem. Collision will also be taken care of because the spell entity has a collidable component. I now plan to add that an enemy ship goes on fire if hit with a fireball, or is frozen and slowed if hit with a ice bolt, and feel I can do this quite easily just with adding or removing components on the fly...

Now I have had a peek at the entityx source code.. it is some serious looking stuff, I have no Idea what is going on. (this probably applies to any ECS framework)....

So finally to my question, roughly how would I achieve the same sort of behavior (as in this spell example), without using ECS. From my readings on the forums, there are still Systems, which process the game logic, but how do they pick up what has to be done? And it seems 'entities' still exist, but not so much as an ECS entity, just a 'game object entity'. Basically what do the systems process, and how do you program this kind of flexibility? How do I create my 'spells' on the fly like this? It does seem like ECS by default is nicely decoupled as game code should be (I can comment out any one of the systems and the game will still run, just without that systems functionality..). Again, do the same concepts hold for non ECS game code?

I plan to program this same 'example scenario' without using ECS, hopefully to make me a better programmer. As amazing as it is for games, I feel it is not actually improving my programming, and makes everything 'too easy'. And yes I do want to program a game, but with the primary objective of learning C++.

Thanks

Edited by SteveHatcher

##### Share on other sites

As such an ECS is a component based architecture.

The use of inheritance here made me chuckle.

Edited by Alpheus

##### Share on other sites

Honestly... ECS is pretty much a flavor of OOP. Just a noob friendly version. OOP is intended to make as much of your code reusable as possible, or provide common low level interphases. It's really hard to explain... as I'm one of the many people who was taught it in it's "Traditional" way >.<

##### Share on other sites

Whilst not 100% accurate, I generally say a game architecture uses an inheritance based system if a game object inherits from more than one ancestor. I.e Object <- MovableObject <- Enemy <- BadMan

If minimal inheritance is used, i.e the architecture prefers composition to inheritance such as Component <- Position and then a position component is added to multiple objects, then I would suggest this one uses the component entity system.

That is in C++. In C, I find the best way for OOP is the component entity system since large chains of inheritance can get complex.

##### Share on other sites
OP: I think where some of your confusion comes from is the boilerplate code that frameworks such as EntityX use under the hood in order to implement their behavior. Part of the complexity involves structuring an object based on some bit of data that describes the structure of that object. For example, it is easy enough to 'compose' an object using concrete members to create an aggregate class:

struct Thing
{
Position pos;
Orientation orient;
Velocity vel;
OtherData d1;
SomeMoreData d2;
};

Such structure is enforced at compile-time, making ad-hoc object description cumbersome. Such a composition structure can be every bit as rigid as a deep hierarchy tree, which also is enforced at compile-time.

Composition frameworks build a system where an aggregate object can be described at run-time, instanced at run-time from a data description. Objects in these frameworks are ad-hoc in nature, and quite often instanced through a system that reads a data file in some format, and populates a generic container with a list of components. The structure of the object is not determined at compile time. Due to the flexibility of such a system, quite a bit of seemingly-complex boilerplate code is necessary. That is what EntityX and others offer: they write the boilerplate so you don't have to.

Essentially, such a framework needs to implement a few standard behaviors. 1) Construct an aggregate object from a descriptor of components. 2) Facilitate communication between objects and components (ie, via event passing or some other scheme) 3) Handle update/render/etc... main loop functionality 4) Provide tools for object lifetime management, instancing, serializing, etc...

While the concepts of a composition-based framework are relatively simple, the concrete execution of them in C++ quite often involves some fairly complex code. Additionally, such a system is STILL probably going to make extensive use of inheritance. For example, an object that implements the basic container for a list of components works well if all components inherit from a base Component class, to enable storing them in a single vector. Objects that can receive events work well if they inherit from some sort of base EventReceiver class, so that the core systems can hand off an event to an object without caring about its ultimate type.

##### Share on other sites

a game object inherits from more than one ancestor. I.e Object <- MovableObject <- Enemy <- BadMan

Inheritance means it should be exactly substitutable as a replacement.  That is NOT what you are doing here.

In that specific example, what happens if you need an enemy that is not moveable?

There are many other similar examples, making something that jumps, something that flies, something that swims, but then nightmares occur when you need to make JumpingAndFlying, JumpingAndSwimming, FlyingAndSwimming, JumpingAndFlyingAndSimming ... Don't go there.

Game objects tend to be COMPOSED OF other behaviors and properties, so composition is the right tool.

Inheritance is an exact "IS A" relationship that requires perfect substitution. Inheritance is also one of the strongest relationships you can grant inside code. (In C++ specifically, the only stronger relationship is friend.)

Inheritance can be useful for interfaces, where a leaf object can inherit from multiple interfaces and abstract base classes. But otherwise, inheritance should be thoughtfully considered and normally rejected in favor of composition.

##### Share on other sites

There are two different object-oriented programming (OOP) techniques in your toolbox ; Inheritance and Composition. For whatever reason, OOP education tends to ignore composition, and as a result OOP is synonymous with inheritance. ECS's happen to use composition, so they seem revolutionary and new at first glance.

However, like all toolboxes, sometimes you need a screwdriver, sometimes you need a hammer...

1. 1
2. 2
3. 3
4. 4
Rutin
13
5. 5

• 12
• 16
• 9
• 14
• 10
• ### Forum Statistics

• Total Topics
632657
• Total Posts
3007680
• ### Who's Online (See full list)

There are no registered users currently online

×