Search Unity

Inter Component System Communication

Discussion in 'Entity Component System' started by Monkeydl_1929, Jul 15, 2018.

  1. Monkeydl_1929

    Monkeydl_1929

    Joined:
    Jan 16, 2017
    Posts:
    4
    How to communicate between two Component Systems...?

    I seem to keep getting the error "ScriptName" cannot be used as a component enumerator.

    I am using Hybrid ECS to try to write a separate Input and Player Controller scripts where I get the input system to inherit from the Player Controller System which inherits from the ComponentSystem.

    Can someone help me with this. Thank you in advance!!
     
  2. zulfajuniadi

    zulfajuniadi

    Joined:
    Nov 18, 2017
    Posts:
    117
    You can inject system into another system:

    Code (CSharp):
    1. [Inject] InputSystem inputSystem;
    2.  
    3. protected override void OnUpdate()
    4. {
    5.     var mousePosition = inputSystem.mousePosition;
    6.     ...
    7. }
     
  3. floboc

    floboc

    Joined:
    Oct 31, 2017
    Posts:
    91
    And concerning your usage, are you sure you need these systems to communicate ???

    The InputSystem should be responsible of updating some InputComponent that your player has, then the ControllerSystem should consider all players that have an InputComponent and apply movements, etc to them.
     
  4. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Yeah it is generally better to communicate via data, as ECS is data-oriented design.

    It is good to design so that system do not know about each other, but they wait for data that someone will eventually produce. Only you as a designer know which system is going to produce a data for this system. (They do need know about each other at only one point that is at [UpdateBefore/After] so that the entire flow is complete in 1 frame.)

    For injecting system there is also an advantage that I found. The 2 systems will no longer be completely decoupled is a disadvantage, but when you manually CreateManager for the world you get all the related systems at once. It looks through recursively from all system inject starting from the system you want to create and it really helps in testing when you know you create one system for the test and all of the call to it is usable because all of its dependency are also created. For decoupled design you would have to instantiate all other related system by yourself, as an action to your single system will just produce data and if there are no other system to pickup data then nothing happens. If this is the kind of system relationship you want then there is a merit in doing this.

    For example I have 4 systems which is really helping each other from a single call to just one of the 4 public method without producing any data to ECS data storage. For this design making each system throws a tag data as a message for other system to start the next work looks cumbersome and system injection kind of relationship looks much better, then I can treat all 4 as 1 big system.
     
    Last edited: Jul 16, 2018
  5. floboc

    floboc

    Joined:
    Oct 31, 2017
    Posts:
    91
    THen why in your case isn't it only 1 system ? Can you give more insight on why having multiple systems injecting each other is particularly useful in your case ? It's just pure curiosity on my part :)
     
  6. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    It is just a way to group and name functionality of those system separately to keep me sane. I could get them all in one file or several files with `partial` but just having a name for each feels like a nice design I think. Also Unity ECS is very verbose if I merge them all it would be ~2000 lines.

    Also I want each one of them to feel more like a tool other system could partially select and use. Normally almost all of my systems run via OnUpdate, which is registered to the game loop by the default world creation code. But these 4 does all has empty OnUpdate, (and I put this.Enable=false on OnCreateManager to further preventing the loop runner from executing the empty OnUpdate) they are systems which is meant to be exclusively call via their public method, accessible with system injection. They can do manual inject (UpdateInjectedComponentGroups) in their own code after some API call because without OnUpdate the data inject will not happen.

    More concretely I have a thing called "Chart" which is a group of ECS data containing many "Notes". I have :
    ChartActionSystem (CAS) : You can save-load those data to binary file and other big actions.
    ChartEditingSystem (CES) : You can modify details of the chart and add/remove some notes. I use preprocessor to exclude this entire file out on production build since I want to edit only in editor.
    ChartInfoSystem (CIS) : It calculate, remember and provide the current state of the chart. (Like amount of notes)
    ChartBakingSystem (CBS) : It has some methods that take considerable time to iterates through all objects in the chart to compute even more data that could be bad for performance if I didn't bake the data beforehand.

    And here's system injections in each :
    CAS : CES, CIS, CBS
    CES : CIS, CBS, CAS
    CBS : CIS
    CIS : none

    So one more advantage is that for other system that wish to use only part of the functionality you will only get what you want. (Not all 4, depending on system injects I wired up) If some other system would like to ask only chart info in the test it would only include CIS and not other to the world for world.CreateManager command, and in test/real game I don't have to bother looking for bugs in other systems. (If there is a bug)