ECS architecture

Started by
30 comments, last by Tanzan 3 years ago

@Juliean thx !

Advertisement

I would suggest different approach with a few notes in general. First, I wouldn't let the movement system know about any of why something is fast, slow or frozen, it should simply act on a set of results created by other systems. So, I would just add a new component which goes with velocity, the “velocity_multiplier” which is a f32. When the movement system executes, it simply multiplies velocity by that value and uses the results in the standard p' = p + v*t equation. The key reason for this separation is that the movement system doesn't get butchered up with a bunch of logic trying to figure out what “v” should actually be, that is left to an external separate system. Given this, I would not use add/remove of a component to trigger the special case here, the modifier always exists in this scenario and is simply set to 1.0f under most circumstances.

Given this new piece of data, add a new system which decides what to set the new modifier too once a frame. All the possible reasons it could be non 1.0f are now separate from the movement code and you can make that as simple or as complex as you desire. The big benefit here is that you can set the value to a range without modifying the movement code. So, for instance someone casts “slow”, modifier is set to 0.5f, the “freeze” spell you mention “0.0f” or how about “haste” 1.25f. This system could even inspect inventory of an entity and change the modifier for encumbrance effects or whatever you want to eventually add.

This still leaves the question of tracking how the state of the modifier is tracked which I leave to a separate solution. For one, I would not use an add/remove component for most things given that the data in question is likely nothing to be concerned with and also if the ECS is an archetype based solution it will be a notable performance impact. Rather, I just create a component that tracks the state information required and attach it to any entity which can be impacted. It could be as simple as three bool's given my description: “is slowed”, “is frozen” and “is hasted”. But typically I want these things on a timer so I again use f32 as a countdown timer for the effects. To slow something you add say 1 second to “is slowed”, the new system will subtract delta time from that and clamp to 0.0f, if the remaining value is > 1.0f, the set the velocity multiplier to 0.5f. Via the separation you can also have combinations which don't overwrite each other: slowed + hasted means that the modifier (depending on order of application you desire) would be 1 x 1.25 x 0.5.

Your needs may be very simple and this is overkill but it doesn't cost notably more to keep the door open to extended functionality through composition of components and systems which is the primary code organizing principle that ECS lends itself to.

@All8Up hello and thx for your reply,

your first 2 paragraphs i agree completely with and its not what for me is ‘strange’ as in pure ecs design.

But you last paragraph is exactly what i try to ‘solve’ pure ecs way (as if it exists everything works fine i just try to see it differently)

i think a system should be strong coupled with its component(s) and not that you have to check multiple states of different components…so the move system should just work with move component (and indeed let other systems adjust speed or whatever) and not check 'if not unconscious && not death && not frozen && not etc i think

thx a lot guys its a very interesting topic

@Tanzan

Firstly, to satisfy your curiosity about how the professionals do it, may I suggest taking a look at this fairly comprehensive break-down of entity component systems by developer Mick West. He worked on the Tony Hawk series of games and when he took it on, he had to refactor/rewrite the engine because of the state that it was in at the time. His article is here:

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

Secondly, it’s worth considering whether an ECS is worth the time invested. For smaller projects ‘ simple games, it’s overkill. If you’re developing an engine, as opposed to a one-off project, then the benefits of ECS are clearer and the time invested better spent.

@ROGRat Thank you rograt,

For me it is also more a study to research what the positive side of different architectures is ,

especially when you go ‘deeper’ into it …at top level most work really good but in the detail i always have the feeling that we need to ‘cheat’ a bit ;-)

to go back on topic, the status component of all8up looks like a nice solution. but again it feels like cheating.

if the monster can see give him eyes and the system rules it, if not take his eyes (temporally) away and the system ignores all functionality related to it…

but what if the player wears shades, is affected by a blind spell or has sand in his eyes etc ;-)…i don't want the see-system be checking all those conditions because it will go out of control and also can give priority problems

your link is really interesting thank you for that.

just again guys ;-) i am not at all a purist and i don't mind workarounds i just like to get the model clear

good weekend!

Tanzan said:
now when the entity can't move anymore because of freeze spell or unconscious, death etc we can handle it two ways

This is more of an overall design question than an architecture implementation concept.

In some games, the design calls for the thing to be frozen solid, immovable. Nobody can bump it or nudge it. Gravity doesn't apply. All motion is stopped. This can be very comical or cartoonish, where even the gravity is suspended while frozen or dead.

In some games, the design calls for the player to stop controlling it, but otherwise the world still interacts. People can bump or nudge it. Gravity applies. They may be paralyzed but still work with physics, they may be a ragdoll, but no matter the implementation the player can't manipulate them while other forces can.

If you go the first route, I'd approach it as something in your physics system. Maybe you could disable the physics component if that's what you are using, clear the enabled flag perhaps. Maybe you could have a self-destructing freeze component that forcefully sets all physics actions to zero. Maybe you could accumulate the action in a local variable and subtract it from the physics settings each update, several games have a frozen state where you can hit many times to build up energy before it becomes unlocked and all applies at once. Or maybe you have some other ideas that better fit your project.

If you go the second route, I'd approach it as something in your player controller system. Maybe a flag that says to consume player controls. Maybe disable the component temporarily. Maybe a check built into the player controller component directly. Maybe a component attached to the player controller component separately, or that applies the change after the controller is updated. Maybe an attribute on the character that the controller system recognizes. Or maybe you have some other ideas that better fit your project.

Both options have been used successfully in a range of games.

There are also options where the two can be mixed. If you've seen it, think of comic situations like Sharknado: A shark can be flying around rapidly, thrown around by the air, but the moment it gets killed it freezes and stops midair, then falls from the sky as though it were in calm air. Basically it enters the first style for a moment, freezing in place against all physics reality, then it enters the second style, tumbling down as though a ragdoll uncontrolled physics object.

@frob Hi Frob,

Thx for your reaction, and indeed it is a functional question which should be designed but implemented in the ECS architecture.

So the question was not specific what but more how and then in relation to ecs.

again thx for you thoughts!

An option I'm a bit disappointed nobody mentioned so far: What about adding a Buff-Component? In nearly every RPG game, there is the point when an item increases movement, I don't assume your game to be an RPG but the same may apply here. So instead of getting a workaround solution for a emi special issue, you should generalize your game for using different kinds of (De)Buffs, e.g. for movement. This way you can apply a Death-Debuff to your hero or any other enemy/character in your game and let that have an impact on movement as well (or controlling the character). This also opens up an option for necroing the character by simply remove the death component from it

@Shaarigan Hi Shaarigan,

thx for your reply and buffs and debuffs are already included in this conversation its all in the name ! ;-)

a buff component could increase the speed which the movement system uses to multiply the basic movement with.

it is a good example how strong ecs can be if you just would use (timed) components to add and to remove from an entity…the entity is buffed or not, simple.

But the problem starts if you want to temporally don't want to be able to move anymore, nice ecs logics would be to just remove it like the buff/debuff…but then you have to keep score which (assembly and/or archetype) component the entity had….flying , walking crawling…

and if you use an extra component to ‘block’ the movement e.g. frozen, hold spell ,unconscious component…then your movesystem has to check all those states which will be fast exploding…

right now i just gave all components an active boolean which all the system can set….doesn't feel ‘ecs’ but hey ;-)

Tanzan said:
and if you use an extra component to ‘block’ the movement e.g. frozen, hold spell ,unconscious component…then your movesystem has to check all those states which will be fast exploding…

This sounds like you are missing a level of abstraction at this point. There is many ways to add the abstraction, off the top of my head these components can be all of the same type, or have the same ‘tag’ that tells the move system that they affect movement speed, and a multiplier it can read (the same way for every such component). That way, it doesn't have to know about all the specific components, it's enough if it knows about the ‘concept’ of a component that can affect movement.

This topic is closed to new replies.

Advertisement