Search Unity

Job with optional component? how to Entity -> Game Object? Events on entity?

Discussion in 'Entity Component System' started by Suike, May 11, 2019.

  1. Suike

    Suike

    Joined:
    Jul 25, 2013
    Posts:
    16
    Is there a way to specify an IJobForEach with one or more optional component?
    I saw the FluentQuery sample on GitHub but it doesn't use an IJob and do 2 iterations, one for entities with MovingCube without MoveUp, and other for entities with MovingCube and MoveUp. Isn't there a way to just iterate through entities with MovingCube having MoveUp as an optional component? For 1 optional it is kinda trivial, but when you have a system with 2 or 3 optional components do I have to code a system for each combination of components?

    I've made a simple game using Pure ECS, just some objects falling and the player move sideways to catch them. But I've only made the logic, now I would like to spawn game objects and set them up with an animator and other MonoBehaviours that read the Entity component data and show some stuff like particles and animations. I currently made a script where I assign an entity to each game object and have them do some stuff, but I don't know if that the best way. Can someone point me out if I'm doing it right or there is a better way? The hybrid examples and approach I saw were just going the other way, you have game objects and create entities for them.

    Also, what is the best way to send events from entities to monobehaviours? Let's say on the Pure ECS side I have a system that adds a FruitHitBasket tag component to an entity with the Fruit and physics components when it hits the entity with the basked and physics component, and I have a game object t with a script that references the Fruit entity with Fruit component. Do I really need to check every frame if the entity has the FruitHitBasket to give some visual feedback like showing some particles and them remove the component on the monobehaviour? I would like to avoid that if possible
     
  2. TRS6123

    TRS6123

    Joined:
    May 16, 2015
    Posts:
    246
    For optional components in jobs, you can use IJobForEachWithEntity and pass the ComponentDataFromEntity of the optional components into the job.
     
  3. TRS6123

    TRS6123

    Joined:
    May 16, 2015
    Posts:
    246
  4. Suike

    Suike

    Joined:
    Jul 25, 2013
    Posts:
    16
    Thank you for your answer but I don't think that is quite what I'm looking for. I don't need to convert monobehaviours to entities nor send data or component data from monobehaviours to entities, my components are not hybrid. Everything I need is already on the entities that exist.

    I just want to know the best to get the entity data on a monobehaviour to send this data to existing unity systems that haven't been yet refactored to use ECS (like animator and particle system).

    Im currently doing GetComponentData on Update, but I dont think that is the most efficient way ...
     
  5. TRS6123

    TRS6123

    Joined:
    May 16, 2015
    Posts:
    246
    You can use my implementation for any UnityEngine Component, not just MonoBehaviours. I have already used it for Cameras, Text Mesh Pro, UI Sliders, etc. If a Unity Engine Component is added to an Entity via EntityManager.AddComponentObject, you can iterate through entities with said component via Entities.Foreach in a ComponentSystem, which completely eliminates the need to use GetComponentData in a MonoBehaviour Update. You just can't use jobs to write to/read from UnityEngine Components, because they are managed.
     
  6. TRS6123

    TRS6123

    Joined:
    May 16, 2015
    Posts:
    246
    Here's an example of how I iterate through Sliders (a UnityEngine UI Component) based on the Value of ChargeAmount (an IComponentData):

    Code (CSharp):
    1. using Unity.Entities;
    2. using UnityEngine.UI;
    3.  
    4. [UpdateInGroup(typeof(PresentationSystemGroup))]
    5. public class ChargeHUDSystem : ComponentSystem
    6. {
    7.     protected override void OnUpdate()
    8.     {
    9.         Entities.WithAll<ChargerDelay, ChargerDelayCountdown, ChargeAmount>().ForEach((Slider slider) =>
    10.         {
    11.             if (!slider.isActiveAndEnabled)
    12.             {
    13.                 slider.value = 0f;
    14.                 slider.gameObject.SetActive(true);
    15.             }
    16.         });
    17.         Entities.WithAll<ChargerDelay>().WithNone<ChargerDelayCountdown, ChargeAmount>().ForEach((Slider slider) =>
    18.         {
    19.             if (slider.isActiveAndEnabled)
    20.                 slider.gameObject.SetActive(false);
    21.         });
    22.         Entities.WithAll<ChargerDelay>().WithNone<ChargerDelayCountdown>().ForEach((Slider slider, ref ChargeAmount charge) =>
    23.         {
    24.             slider.value = charge.Value;
    25.         });
    26.     }
    27. }
    28.  
     
  7. Suike

    Suike

    Joined:
    Jul 25, 2013
    Posts:
    16
    Hmm, I got it. Thanks for the example.

    So instead of doing it on the monobehaviour update I send the UnityEngine.Components as ComponentObject to the entities and make a normal ComponentSystem (not a Job) to update it.
     
  8. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Optional components on the main Thread you can use EntityManager.HasComponent & EntityManager.GetComponentData using Entities.ForEach with the first parameter being the Entity.

    On a job you can use ComponentDataFromEntity<> to do the same thing.
     
  9. Suike

    Suike

    Joined:
    Jul 25, 2013
    Posts:
    16
    Thank you for your reply, I appreciate your response during the weekend. I know it is a lot of work but I believe a lot of the class/methods in the package docs lacks a description, and since the framework is currently under development some of the samples/tutorials/experiments I find are mostly outdated.

    Also, I dont know if it is possible, but any chance Jobs/Systems support contravariance in the future?

    Something like:
    Code (CSharp):
    1.  
    2. public interface IMovement : IComponentData
    3. {
    4.     float3 MovementVector { get; }
    5. }
    6. public struct LinearMovement : IMovement
    7. {
    8.     //some data
    9.     public float3 MovementVector { get { return vector; } }
    10. }
    11. public struct NonLinearMovement : IMovement
    12. {
    13.     //some data
    14.     public float3 MovementVector { get { return anotherVector; } }
    15. }
    16. public class MovementSystem : ComponentSystem
    17. {
    18.     protected override void OnUpdate()
    19.     {
    20.         Entities.ForEach((ref Translation translation, ref IMovement[] movements) =>
    21.         {
    22.             for(int i = 0; i < movements.Length; i++)
    23.                 translation.Value += movements[i].MovementVector;
    24.         });
    25.     }
    26. }
    (Im not really sure if this is possible because property getters are mapped to methods, so it would need a function pointer on the C++ side, which would make it reads from another memory adress and make it non-linear. But I dont know how IL2CPP or Burst or how you compile the C# code to C++, so maybe? :D)

    Or any chance EntityManager get a method like GetComponentsData<T> to get multiple components which inherit from the same interface (that inherits from IComponentData)?
     
    Last edited: May 13, 2019