Search Unity

Discussion General questions about ECS

Discussion in 'Game Design' started by BIGTIMEMASTER, Jan 16, 2023.

  1. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    I'm trying to learn more about the Entity Component System model, and would love to know if anybody can help me test my knowledge here. Looking at a high level example, my main concern isn't so much that this is "true" ECS, but rather, this example achieves the general goals of ECS insofar as the following goals are concerned:
    • more modular code (can remove and change systems/components without widespread effects)
    • more maintainable code (related to modularity and also effected by generally more compartmentalized code with more clear responsibilities)
    • flatter code (there are no real hierarchies to remember)
    • fewer communication pathways (e.g. systems are largely self contained, entities never cross-communicate, so overall the amount of places where there can be a bug due to transmission sent but not received is fewer)
    So, example:

    Say its hunting game. Shoot an animal, it becomes wounded and will eventually die. For this we need:

    1. An entity
    2. Wounded Component
    3. Death Component
    4. Wounded System
    5. Death System

    (there are many other components to define, like for the AI behavior, but I just boil this down as its really only about the communication between components/systems)

    So animal is shot. That is an event in the game world. One way or another, this event needs to get to the Wounded System. The entity in the world probably should not know specifically about the Wounded system, but rather the entity should just broadcast that it is has been wounded, and the Wounded System watches for this broadcast. Or, entity can interface to the Wound System, or perhaps to a central relay board, which will intake reports and then relay them to the appropriate system.
    This way, entity only ever need to report their events to a single point.

    This broadcast may be something like,

    OnWounded (EntityID, InitialDamage, HitOrgan, CaliberBullet)
    {initialDamage + (hitOrgan * CaliberBullet) = BleedoutRatePerSecond}


    Now the Wounded system knows which array element to grab the current health state from, it can run this operation and pump updated state back into the health component.

    Suppose the Health reaches 0 though. It should be the Health Component who broadcast this important report, right? Components are not meant to hold logic though?

    This is where it gets a bit confusing to me. Components define the behavior that exist in the game world. Basically we look at a list of components, then we know everything that can happen in the world. Just like reading a book.

    Systems depend on components. Because systems only have context insofar as what components they operate upon. Therefore, systems are coupled to components, but components are not coupled to systems. Do you think this is correct to say?

    If correct, then we could say that Systems must listen to components, and events broadcast from the game world. Systems should never communicate system to system, because systems are the things that are most ephemeral?

    That seems to make the most sense to me. Do you agree? Again, is it perfectly true ECS? I dont really care about that, and my primary goal is not performance for a complicated game, but rather an easier to understand and maintain architecture for a tiny team. And, at least speaking for myself, this general idea of ECS just seems to make sense to my way of thinking, compared to OOP (which I liken to herding cats, because there is all these little things with their own little personalities and trying to keep track of them and make them play nicely is a real chore).
    So a system like I've described, does it achieve a high degree of decoupling? Is the data flow that I've described in line with the principles of ECS? Do you see issues with modular and extensible code base this way?

    Thanks a lot for any input
     
    Last edited: Jan 16, 2023
  2. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    Another practical example where it is hard for me to determine how data should flow:

    Say you have a time of day system. Every three hours, system fires off and changes the state of some animal AI. So they go from eating, to drinking, to moving, to resting, etc...

    When this state changes, now the animals need to actually perform whatever animations and movement is needed. So the component ought to send out a broadcast so that the relevant systems can start running? Like a Migration system that will take charge of moving animals to new target location, and an animation system that says, "if animal is in X state and speed is X, play this animation."

    So in this case data goes from System to component, component reports state change (just a general broadcast, no specific target), and other systems which are interested in this state change broadcast can listen for it.

    This way I think we keep it such that systems depend on components, but never components to systems.