🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

ECS architecture

Started by
30 comments, last by Tanzan 3 years, 1 month ago

@Andor Patho Hi Andor patho, that sounds interesting! could you explain to me better?

In my opinion if you generalize the components (inheritance) that's what you describe i guess ? then you would sooner or later get the problem that members (components) of the entity will fall in 2 groups…with all the problems connected with that.

But again maybe i am indeed missing something ? i hope so ?

Advertisement

@Tanzan Inheritance is one way to do abstraction, but it has its problems (like you pointed out). It's hard to describe the best way to do it for your specific situation, without knowing the details of your implementation and your requirements, but I will try to describe one possible implementation (of many):

The buff/debuff or status effect affecting movement doesn't have to be a single component. It can consist of one specific component (e.g. FreezeComponent, SlowComponent) in combination with a generic component (e.g. MovementEffectComponent), and both components are added/removed to the entity when the status effect starts/ends. The specific component handles specific stuff to that one status effect, and doesn't interact with the movement system at all. The generic component is known to the movement system, and is shared (part of) all status effects that affect movement. If you have more than one effect active that affects movement, you will have more than one MovementEffectComponent for one entity, and some kind of rule in the movement system how to combine their effects (in the simplest case maybe the MovementEffectComponent can just contain a single multiplier value, and all of them are multiplied together with the max speed of the entity to get the actual max speed).

wow Andor Patho,

That is indeed a interesting approach i will sure look into it , thx for your thoughts !

Sounds like you have a really “static” view of your ECS, while there are way more options to tackle it than you might think of. Lets for example point the movement out a bit more: There can be multiple movement components on your entity, they can be static and temporary at the same time like for example if you wear “Boots of Incredible Speed +5” together with “Coat of the Wind, Speed +2”, be in a swamp which has a temporary effect of slowing the character down by 3 while walking in muddy water and maybe a temporary debuff from being targeted by a frozen spell. So you have 4 states your system needs to handle: Character-Speed + 5 + 2 - 3 * 0. Now you have different options how you want to do it.

One solution I can think of right now is to add 4 times the same component, remember that in ECS a component is just plain data and unless in systems like for example Unity3D, they can't have any logic. Sonow we need a way to handle those data, in order to add/remove effects when you equip or remove items, walk out of the muddy water or the spell starts to disappear. To speed things up, a MovementModifier component could be added which also has some kind of ID (a string) to be identified by other systems like the BuffCooldown system or the InventoryEquipment system. They can then react to those components with an ID andadd/remove just them without adding/removing anything else.

And you can also create a nice UI from all your buffs/debuffs with ID => Display Text

@Shaarigan indeed i am probably way to static shaarigan ;-) i just try to play around with it.

i'm a pretty old programmer who started procedural languages ( long long time ago ";-) ) and have been raised with oop (the time that inheritance was the best invention since the wheel, its hard to not fall back in old behaviours)

Thx all again !!!

If a user is frozen, how would you handle the “frozen” part? Would the user have a frozen component added, which would include adding icicles on the character to show he's frozen, as well as a cracking sound when he becomes unfrozen? If so, would it be responsible for removing and holding the movement component, and adding it back? Or would the frozen component set the pause and unpause attribute in the entity's movement component?

Many different ways to handle it, good luck finding the right one!

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

@BeerNutts Hi man, thx for your reaction…

For me it is not about the real implementation but more about how to do it ‘right’ according to ecs architecture.

So for example make it as complicated as you can imagine…loads of components are connected to an entity which all give them attributes where systems react on accordingly so we get behaviour.

For me the problem is how to manage it without checking 100 of states..probably my mind is corrupted by oo i know so i would like to know how the professionals do it. a groupofstate module is for me now the most interesting

so you could have an immobilized component which has or direct bools or also components like frozen,hold person (spell) and unconcsious , dead etc. and then let each of those components be controlled by there own system…this could work fine….until you have states that fall in more then one group…

it constantly feel like i am ‘breaking’ the ecs architecture but again i might be corrupted ;-)

Tanzan said:
so you could have an immobilized component which has or direct bools or also components like frozen,hold person (spell) and unconcsious , dead etc. and then let each of those components be controlled by there own system…this could work fine….until you have states that fall in more then one group…

I believe you're spending too many cycles trying to over-engineer a solution rather than implement something that functions and then iterate on it when you identify a problem.

That said, if we take freezing an entity, that can involve a few aspects:

  • Physics component sets adequate mass to avoid force/movement being applicable, i.e. doesn't move.
  • Model's animations are suspended.
  • Particle effects or additional game objects may be spawned, such as icicles.

The above already involves several systems including Physics, Animation, Particle, and the EntitySpawner. How you intend to represent this frozen state can be as simple as having a boolean flag on the PlayerController or you could represent it more specialized with the introduction of a Frozen component. There isn't a right answer here and performance will always be the deciding factor. So for the time being, pick a pattern and go with it.

With regard to being dead, that can easily be derived from a Health component with a value of 0. At the moment it reaches 0, the character can no longer move, possibly using the mass trick like we did for the frozen scenario. The HealthSystem would notify the animation system to play the death animation. The death animation itself has keyframes that also can notify other work to be done, such as playing sound effects as the death animation plays back.

You will inevitability hit a situation that will make you re-evaluate certain decisions and that's normal, embrace that, refactor, and your code will get even more resilient. But spending time trying to find the magic bullet just ends up being wasted cycles you could have been moving forward making the game.

@crancran wow thx a lot for your reply !

it feels indeed like i am overengineering stuff..but its just that everything ‘fits’ perfectly in the architecture and then all of a sudden not anymore…and then for me it feels like i'm doing something wrong (according to the architecture)

I hit many problems because i don't have many limitations in my game…i am busy to make a text based adventure (mud) based on AD&D rules with ecs as framework; best option? i dont know but i want to try it. reason i started it with ecs is the seemingly dynamic way of aggregating stuff.

anyway thx again all, it helps me order my thoughts!

regards,

Tanzan

I'm not sure if you've seen the GDC talk by Timothy Ford where they implemented ECS in Overwatch at Blizzard. If you haven't seen that talk, I would highly recommend it because its super informative. The TL;DR is basically the following:

  • Components have no behavior, no functions, simply contain state.
  • Systems have no state, only functions and no member variables.
  • Behavior dependencies are controlled by the tick order of systems.
  • Singleton components are necessary, where only 1 exists per scene such as Input but should be scene scoped.

He also discussed the problems they faced when they implemented Kill Camera playback where they had components such as Input designed to be global variables, scoped to the entire engine and realized that created a problem. Their solution was kinda ingenious where they decided to store “Singleton Components” on the world, not globally and this allowed them to have the game simulation maintained in one World while also having the Kill Camera feature simulated in a second World.

My point is you will almost always find points in development where things feel like they fit and then immediately don't; that's normal. What's important is when you do reach that point, take the time to step back and not only look at the immediate issue but the entire architecture as a whole. You might find that simply shifting something around (i.e. Kill Camera) solves all the problems and that the architecture/design philosophy you've been using isn't necessarily the problem.

Tanzan said:
I hit many problems because i don't have many limitations in my game

Well again programming is iterative and our first implementation of something will never be perfect. As more features get added, the shortcomings of part of the implementation will become more obvious and its at that point to stop back and revisit what you need. In addition, if you have to apply limitations to your version of the game just to get something functioning, there is nothing wrong with that either. It's better to feel like you've accomplished something and see it at work rather than trying to tackle everything and just having a heap of code that doesn't yet function imo.

This topic is closed to new replies.

Advertisement