Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

How to implement a logic that requires multiple iterations over the same systems in one frame

Discussion in 'Entity Component System' started by Dmitry_Kozlovtsev, May 29, 2018.

  1. Dmitry_Kozlovtsev

    Dmitry_Kozlovtsev

    Joined:
    Mar 2, 2018
    Posts:
    13
    For example, if there is a logic in game that requires to apply damage on all character in area of effect after one character have received damage, in that case all the damage calculation systems should be run once again.
    Example flow

    Some system adds ApplyDamage component to CharacterEntity
    ArmorSystem - reduces damage
    TakeDamageSystem - reduces health
    ThornsSystem - applies damage to all enemies in some radius based on damage taken
    ...
    Somehow ArmorSystem, TakeDamageSystem, and maybe even ThornsSystem should be run again before next systems are run.
     
  2. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,554
    I think we can [Inject] SystemName and then explicitly call `.Update` on it. (Haven't had any situation to do this so I don't know whether it works or not.)

    (But in this situation I think making thorn system runs earlier than have that also issue another damage component so that the damage dealing system can do it together in one go would be better)
     
  3. Afonso-Lage

    Afonso-Lage

    Joined:
    Jul 8, 2012
    Posts:
    70
    Or since it's another type of damage, you could let it run again on next frame and pass thru all thoses systems as an ApplyDamage over surrounding enemies. If you game runs at 60 fps, one frame of delay is 33ms~.
     
  4. Dmitry_Kozlovtsev

    Dmitry_Kozlovtsev

    Joined:
    Mar 2, 2018
    Posts:
    13
    ThronsSystem cannot be run before TakeDamage as thorns damage depends on how much damage was taken after all the armor reduction, and it itself reduced by armor. So example is designed in a way that there is no way around calling systems many times per frame =)

    Is there any documentation on how [Inject] works in case of systems, are they excluded from run? can system group be injected?

    I didn't ask for workaround, the game logic may require it to be done in single frame.

    There is also another related case when order of the systems should be dynamic.
     
  5. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,554
    Currently the only official place that I learned this is possible is : https://github.com/Unity-Technologi...tent/ecs_in_detail.md#injecting-other-systems there are no other examples that I know of.

    I have one system inject in my game just so that I could directly grab it's `NativeArray` public field. That system still runs even with injection, so I can confirm they are not excluded from run. I think there is an attribute to prevent any system from being inserted into the system runner but I forgot which one.

    For the time being you could examine the source. In `ComponentSystemInjection.cs` is where it reads [Inject] attribute. The class injection would go here.
    Screenshot 2018-05-29 17.06.25.png

    After that it checks if it is a subclass of `ScriptBehaviourManager` or not. So I guess that means a system group injection will not work.

    Screenshot 2018-05-29 17.11.01.png
     
  6. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    They are not excluded or disabled, the injected system is simply a reference to the system of that type which exists in the same world.
     
  7. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Manually injecting those systems and then re-running those systems explicitly using System.Update() when you need it seems like a fine solution.
     
  8. Dmitry_Kozlovtsev

    Dmitry_Kozlovtsev

    Joined:
    Mar 2, 2018
    Posts:
    13
    I think it can work, thanks, at least now I know that doing it will not mess up something inside the framework
     
  9. Dmitry_Kozlovtsev

    Dmitry_Kozlovtsev

    Joined:
    Mar 2, 2018
    Posts:
    13
    One other question will injected systems update their injected groups each run?
     
  10. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,554
    Without actually trying it but just from scanning roughly through the source code : by calling `.Update` it runs `InternalUpdate` on the system. That method in turn runs `BeforeOnUpdate` then (your) `OnUpdate`. The method `BeforeOnUpdate` has `UpdateInjectedComponentGroups`. That method then runs `UpdateInjection` on each of your component groups to give it a new data. (CopyStructureToPtr). So I think yes, each `.Update` refresh the injected group.
     
  11. Dmitry_Kozlovtsev

    Dmitry_Kozlovtsev

    Joined:
    Mar 2, 2018
    Posts:
    13
    Thank you, 5argon, that is really helpful.
     
  12. mike_acton

    mike_acton

    Unity Technologies

    Joined:
    Nov 21, 2017
    Posts:
    110
    If you want to continue to use automatic system management and not do it manually -- Another method might be:
    Generic systems are not run automatically. (Makes no sense for them to be.)
    So you can make your system a generic and derive multiple concrete systems which will will be run.
     
    vanxining and 5argon like this.
  13. Dmitry_Kozlovtsev

    Dmitry_Kozlovtsev

    Joined:
    Mar 2, 2018
    Posts:
    13
    Is there an example on how to use manual system management? For now documentation is rather lacking and one has to experiment with the API, hope that will be improved in the future.