Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice

[Tutorial series] Making an RTS with pure ECS

Discussion in 'Entity Component System and C# Job system' started by skhamis, Jan 13, 2019.

  1. skhamis

    skhamis

    Joined:
    Mar 3, 2017
    Posts:
    19
    Hey all!

    I am starting a new tutorial series that ill try cover the most "updated" way to make a game with ECS. I felt like there might not have been enough examples for making easy-to-understand systems. I'm going to target RTS as I feel it suits very well to something like this (alot of units, various types and things happening, etc). I have the full code on GitHub and will probably try to keep it updated as much as possible. Looking for feedback and if any of the code looks wrong!


    Link to the repository that will be updated: https://github.com/skhamis/Unity-ECS-RTS
    Link to the playlist where I'll add new videos
     
    Last edited: Mar 1, 2019
  2. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    1,153
    Didn't watch video (I'm personally just not a fan of video tutorials) but I had a read of your code and it looks solid.

    I look forward to watching it progress.
     
    Last edited: Jan 13, 2019
    hippocoder likes this.
  3. skhamis

    skhamis

    Joined:
    Mar 3, 2017
    Posts:
    19
    I appreciate reading the code! I definitely know there are some people who like to see everything piece-by-piece and some people who prefer to just be given code and decipher what they need from there. Hopefully I can help people from both groups!
     
    Antypodish and Ylly like this.
  4. NoDumbQuestion

    NoDumbQuestion

    Joined:
    Nov 10, 2017
    Posts:
    169
    I read the code
    I wonder do we need to remove and add component to Entity. Just to tag it as selected.

    As far as I understand how ECS work, add/remove component from entity move it to different chunk since it is a new archetypes. And Command Buffer is not consider cheap.

    Would it be better if Selected Component have bool type or using SharedComponentData.
     
  5. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    1,153
    It's actually unlikely to move it to a new chunk in this situation as there will likely only be a single 'input' entity so the chunk will just be redefined. (And when the next build drops with singletons it'll probably made into that.)

    It's definitely a valid point though. Better off setting than adding/removing, I do not agree with the SharedComponentData suggestion though.
     
  6. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,057
    This right
    This not right :) Using SCD do same things, because it's per chunk basis based on SCD value, it's similar as add tag - it's moving entities in different chunks.
     
    Last edited: Jan 15, 2019
  7. skhamis

    skhamis

    Joined:
    Mar 3, 2017
    Posts:
    19
    Agree with the commenters that ShareComponentData shouldn't be used for anything that's changing often (like selecting units). From the docs:
    As for SelectedComponent being a component on all PlayerUnits and then just set the value to true/false. I felt like other systems that need to do anything with the selected units (move, attack, see available stats, etc) can filter easier rather than having to check component.isTrue. Though the more I think about it, it definitely might be more performant -- will have to run some tests!
     
  8. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    4,084
    Surely we don't want every system running through thousands of entities, to check true false, if we dont change state often. Hence component taging can be useful.
    Probably wont be changing state of all units per same frame anyway. So taging can be naturally distributed over the time. This way, reducing number of unnecessary entities iterations on other systems.
     
  9. NoDumbQuestion

    NoDumbQuestion

    Joined:
    Nov 10, 2017
    Posts:
    169
    On contrary, I think iterate over 100000 every entities to check if-else is much cheaper than component tag different kind of archetype.
    Like if we pick different kind of minions with different components then each of them will become new archetype type and each in seperate chunks or redefine like tertle say.
     
  10. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    4,084
    For one system may be.
    Likely project specific, what requires.

    But if you have few system, which checks bool value, instead filtered entities by components?
    So lets say having 5 systems, which iterates through 100k each.
    Instead of having maybe 10k per system, per frame.
    And if you don't change status every frame, as I said earlier, that massive performance saving.

    Some nice comparison benchmark would be welcome.
     
  11. NoDumbQuestion

    NoDumbQuestion

    Joined:
    Nov 10, 2017
    Posts:
    169
    Then what would you think of the hierarchy tree sub-system design? Main system pass interest data over to sub-system.

    Starting with a tag system process 100k check if-else tag entities and pass 10k tag entities to sub-tag-system and 90k to sub-notag-system. This way we can handle different type of tag to different system in one go (may not optimal when made new data to each system)

    I think if design this way, more control over tag-system specific. Would it better than make system query for different component tag?

    Edit: this is for game that need lots of tag like minion type need different solution. Not simple isclick tag like above
     
  12. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    4,084
    You need weight, where you would use tag, and where bool of course.

    IsAlive tag, is a good example of use tags, to reduce count of entities for system (s).
    ReadyToAttack can be another use.
    Or retreat tag.

    But in case of fire now, if firing / attack is rapid and often bool iteration can be suitable.
    However, my system probably will be already filtered, by some form tag, as CanAttack / CanFight etc, since these are not need be toggled every single frame.

    Again, last thing I want, is having multiple system iterating through all entities, when not needed.
     
  13. jooleanlogic

    jooleanlogic

    Joined:
    Mar 1, 2018
    Posts:
    244
    They both have a place as Anytpodish showed good examples but polling the many for the few isn't a good strategy to use by default. It could take a toll over time as your game grows and would be harder to identify and fix later on as a performance issue.

    Tagging has it's downsides too though and polling has increased benefits vs tags within the job system.

    There is a thirdly option which is reference entities where you spawn a new entity and leave the target unaffected.
    Code (CSharp):
    1. Selected : IComponentData { Entity target; }
    You spawn a new Entity with Selected component and then the processing system just updates the target Entity position via ComponentDataFromEntity.
    This could be useful if you have ordered entities which can't move or heavy entities (dozens of components) which could be overkill to move for the sake of small operations.
     
  14. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    799
    And not to forget, that you would also only need to iterate through changed chunks. I would also love to see some benchmarks around this, to derive at some guiding design principles
     
  15. LazyGameDevZA

    LazyGameDevZA

    Joined:
    Nov 10, 2016
    Posts:
    70
    The most important aapect of tagging to remember is in how often the tag is added/removed. Richard Fabian's book on Data-Oriented Design talks of the concept as existence based processing.

    His example is that a health recharge system that only does processing when some entity is damaged meaning that if the entity is at full health it's health component is removed and the same for when the entity is dead. This removes the need to check if the entity is at max health thus allowing the CPU to only focus on processing what data actually exists.

    It does depend on your use case though so it's most important to understand what your data is doing.
     
  16. skhamis

    skhamis

    Joined:
    Mar 3, 2017
    Posts:
    19
    Instead of making a new post I will just bump this one with my part 2! I also show how to update to 0.0.21 package (and update MeshInstanceRenderer to use a ISharedComponent)

     
    GliderGuy, Rewaken and Antypodish like this.
  17. Garmbrael

    Garmbrael

    Joined:
    Jan 12, 2018
    Posts:
    1
    Another great tutorial video! Thank you very much for creating these and helping to educate us poor souls who are still struggling with the concept of how to use ECS. I did notice 2 things though. First, your github link https://github.com/skhamis/pure-ecs-rts is out of date and not actually representative of your current code in the video (namely the "Unit Spawn" component and system are missing). Second, I think you missed a few areas that should have had [BurstCompile] on the Jobs. ;)
     
  18. skhamis

    skhamis

    Joined:
    Mar 3, 2017
    Posts:
    19
    Hey Garmbrael,

    Thanks for watching! Also thanks for the feedback!

    1. GitHub updated, I hope sometime this weekend to start having branches per-video as opposed to just a dump on master once the "core" mechanics are done.

    2. I am actually saving the [BurstCompile] decorator, and burst compiling as a topic in general, for an entirely separate video where I can deep dive into the why and when to use it! Though thanks for keeping me on my toes ;P
     
  19. skhamis

    skhamis

    Joined:
    Mar 3, 2017
    Posts:
    19
    Part 3 released! I try to switch it up and use IJobProcessComponentDataWithEntity to get selecting working and we start creating a custom NavAgent to process smoothly moving from position to final position!

    updated github: https://github.com/skhamis/pure-ecs-rts

     
    GliderGuy and Kiupe like this.
  20. NoDumbQuestion

    NoDumbQuestion

    Joined:
    Nov 10, 2017
    Posts:
    169
    Your navagent not use Navmesh is kind of misleading. But anyway, great start up sample.
     
  21. Micz84

    Micz84

    Joined:
    Jul 21, 2012
    Posts:
    219
    I would pull out an if from select job and put it to execute method of the system so you do not start a job for no work at all.
     
    hippocoder likes this.
  22. skhamis

    skhamis

    Joined:
    Mar 3, 2017
    Posts:
    19
    Continuing the series! Some people asked how to use the Attach component and attaching new entities to existing one so I cover that in part 4 of the series!

    Link to Github: https://github.com/skhamis/Unity-ECS-RTS

     
  23. skhamis

    skhamis

    Joined:
    Mar 3, 2017
    Posts:
    19
    Part 5! I start removing some of the hacks we had and add some basic colliders (Axis-Aligned Bounding Boxes) to have more accurate clicks and set-up the base for computing collision logic!


     
    FROS7, alvivar, Marble and 2 others like this.
  24. skhamis

    skhamis

    Joined:
    Mar 3, 2017
    Posts:
    19
    Part 6, we begin detecting collisions between AABBs and how adding [BurstCompile] really speeds up the jobs! Always looking for feedback and if there is any kind of topics you want me to hit sooner than later!

     
  25. jdtec

    jdtec

    Joined:
    Oct 25, 2017
    Posts:
    32
    Hi skhamis, I've been following this and have found it helpful, thanks for the content.

    I'm also writing an RTS in ECS, might post something eventually if I make any interesting progress. Looking forward to see how yours develops.
     
  26. MartinLyne

    MartinLyne

    Joined:
    Apr 25, 2013
    Posts:
    30
    I'm attempting to follow these tutorials but in video 2 where the Archetype is shown it has Position Component attached, but i don't see how this is done? Could anyone help me out? Shown in the inspector in Pt2 at 7:29.
     
  27. Tyndareus

    Tyndareus

    Joined:
    Aug 31, 2018
    Posts:
    2
    @MartinLyne just click add component and search for it, they are prebuilt components from the ECS package
     
  28. MartinLyne

    MartinLyne

    Joined:
    Apr 25, 2013
    Posts:
    30

    @Tyndareus I have tried that, but it looks like the last update replaces Position with Translation. When I search for Translation is appears as "Translation - deprecated"

    I don't know if there's some other package I need to add or docs are out of date. Even the examples the tutorials are based on seem to have changed.
     
  29. Tyndareus

    Tyndareus

    Joined:
    Aug 31, 2018
    Posts:
    2
    Yeah, thats the current issue with following ECS, everything keeps changing because its still at the design/prototype stage
     
  30. MartinLyne

    MartinLyne

    Joined:
    Apr 25, 2013
    Posts:
    30
    Don't suppose you know any good tutorials for "pure" equivalent for a bootstrap monobehaviour? I'm struggling to do anything without gameobjects!
     
  31. skhamis

    skhamis

    Joined:
    Mar 3, 2017
    Posts:
    19
    Yeah I'm actually waiting a little to continue the series as the changes happening recently were pretty big and kind've wanted to wait till the dust settles a bit.

    @MartinLyne There isn't a "pure" equivalent for monobehavior yet as alot of the systems simply haven't been migrated to the DOTS (Which is their new "ECS" terminology). But In the basic example they do have a way of converting your gameobjects to Entities:

    https://github.com/Unity-Technologi...EADME.md#converting-from-gameobject-to-entity