Search Unity

ECS thinking

Discussion in 'Entity Component System' started by Eldirfar, Oct 6, 2019.

  1. Eldirfar

    Eldirfar

    Joined:
    Feb 9, 2014
    Posts:
    65
    Hello, Im currently starting new after work hours project and I wanted to use all Unity new features like DOTS, Input System etc. In work Im stuck with Unity 2017.4 for now :(
    I have basic knowledge about ECS. I watched some Unity streams, and was at Unite this year but have problems with more complex problems.

    For eg case like this:
    We have ship with front cannon and rear 3 cannons on both sides. Other enemies like tank or tower also can have cannon. What guys you think would be the best approach in ECS?

    Ok simple - I would make cannon an entity with position, rotation and cannon but there goes the harder part. What entity should store reference to cannons? Let's have ship entity that will store references to cannons (we can pass those reference during conversion from GO or should pass it later? How to store those references). Then how to tell them to shoot?
    Input -> Makes input entity
    InputSystem -> process input entities.
    And now I see few options.
    1. InputSystem spawns bullets from list of cannons form ship entity
    2. InputSystem tells Ship to shoot, then some ShipSystem process it. I can have later some tower which also have some cannon that can shoot. I think would be best to avoid entities like "ship", "tank", "tower" but then where to store list of cannons?

    Many questions in such simple example. In GO way there would be just ship with oher GO ther represents cannons. I have hard time with thinking ECS way. Maybe any one have good article/book how to design things in ECS with good more complex examples?
     
  2. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    679
    I struggled with a similar problem when I began looking into ECS, hopefully the example below may help you to find a solution for your issue:

    ECS thinking is about thinking about the data needed to do what you want instead of thinking how the objects can interact with each other.

    So...

    - You goal: shoot with a cannon
    - Which data you need? a "shoot" input, the cannon rotation, the cannon power and maybe other cannon attributes

    The first step here is to define "What is a Cannon entity?". That could be an entity with a CannonAttributes component, or a entity with both CannonPower and CannonMesh components, or something else (just remember to think about the data here, not the entity itself).

    So a possible solution for that is to have e "CannonShootSystem" which process all Cannon entities (all entities with "CannonAttributes component, for example) with also a Shoot component tag, which should be added by another system responsible by the shooting itself and then removed after the CannonShootSystem processed that Cannon entity.

    But then you have another situation...

    - Your goal: tell a cannon to shoot
    - Which data you need? the input itself (let's think about the player only for now)

    You could add to all the player's cannons a "PlayerControlled" component (this PlayerControlled could also store the entity of the player in case of a multiplayer game).

    The PlayerInputSystem then could process all inputs and once the cannon shoot input is received, it pick all Cannon entities with a PlayerControlled component and add the Shoot component tag on it.

    Instead of storing in each cannon which player it belongs to, your player could have a buffer of cannons. This would be a "better" (better is relative) way of doing that, but dealing with buffer may be an additional concept to struggle with so I recommend you to keep things simple until you are comfortable to dig more into all the DOTS concepts.
     
  3. Eldirfar

    Eldirfar

    Joined:
    Feb 9, 2014
    Posts:
    65
    If I have GO ship and children objects cannons how it will look after conversion? I guess cannons will be separated from their parent. Or there is any link to parent/children in ECS?

    I don't think it's the right way (or I'm wrong)

    But this way we will create something like "Ship" component that will store list of cannons. With that approach I see problem that for every type of vehicle or something with cannons I will need to make other components. I think if something is a ship or tank should be defined by set of components not by component per se.

    Writing above I came to solution that I will make FrontCannon tag, and RearCannon tag to define type of it but id don't solves how to get to them.

    Another one. Player can control ship/tank (only one at time), each can MoveForward so I make MoreForward component with speed per s. Where to store max move forward value which is multiplied by input [-1,1]. Which is better MoreForward have second variable max speed or make another component with MaxSpeed?

    I also heard that is better to clear values for eg form ShootTag instead of removing it.
     
  4. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    679
    I think that link may interest you: https://docs.unity3d.com/Packages/com.unity.entities@0.0/manual/transform_system.html

    At some extension you are right, this is not the "right way" but is still a data-oriented approach, you surely would prefer to use buffers over having a weak link like that.

    Here is where you are getting lost and why I suggested the another approach until you understand better about buffer elements. You are right - what it is should be defined by its set of components and not by a single component, I never suggested differently from that, I think that you misunderstood my example.

    To understand better what I mean, is that the composition Player => Ship => Cannons makes sense while authoring and planning how your scene should be presented but the systems that are gonna handle those things doesn't necessarily need to know about that relationship.

    Cannons could belong to ships, to towers, or even to another cannons (why not?) and the system should not care about that - all that it should care is the necessary data to make what it was born to do (like the CannonShootSystem in my example - it was born to make the cannon shoot a projectile so all that it needs is the cannon attributes (could be a single component or a collection of components) and know which of those cannons should shoot (thus the Shoot tag).

    If the FrontCannon and RearCannon have different functionalities, that makes sense. I am not fully aware of your context, however.

    It is up to you, there is no right here.

    You are also right here. But again, keep it simple, don't think about micro-optimizations from the very beginning, first adapt your mindset.
     
    Deleted User and Burlyduck like this.
  5. Eldirfar

    Eldirfar

    Joined:
    Feb 9, 2014
    Posts:
    65
    Thanks. I didn't know about this whole manual.

    If I would use "PlayerControlled" component per Cannon I should use ShardComponent to filter query by player id?

    About buffers
    https://docs.unity3d.com/Packages/com.unity.entities@0.0/manual/dynamic_buffers.html
    So it is basically component that allows to have more than one Component per entity. So if I not wrong on main entity i could have buffer "RearCannon" which is list of all my rear cannons on ship yes?

    Is easier if you know basic structures :)
     
  6. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    679
    Don't know where that ShardComponent came from, but seems like so

    Yes, exactly.