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

Question How to set Data for components on sub objects

Discussion in 'Entity Component System' started by bx3776, Dec 27, 2022.

  1. bx3776

    bx3776

    Joined:
    Nov 25, 2014
    Posts:
    13
    I have a prefab, including an empty parent object and two child objects with mesh and material. I bound ecs components on two sub objects to change the input parameters of materials. It works well in the subscenes. Now I instantiate 1000 Prefab in ISystem, but I don't know how to set different parameters for the components of two sub objects. What do I need to focus on or which API to use?

    Code (CSharp):
    1. public void OnUpdate(ref SystemState state)
    2.     {
    3.         var spawner= SystemAPI.GetSingleton<PlayerSpawnerComponent>();
    4.         var ecb = new EntityCommandBuffer(Unity.Collections.Allocator.Temp);
    5.         for (int i = 0; i < 1000; i++)
    6.         {
    7.            var e= ecb.Instantiate(spawner.player_entity);
    8.  
    9.           //  set Compoent data for primary entity
    10.            ecb.SetComponent<PlayerComponent>(e, new PlayerComponent() { id= i });
    11.  
    12.         [COLOR=#ff4d4d]  //   How to get child entities and set ComponetData for they?  
    13.            //  [/COLOR][COLOR=#a64dff]ecb.SetCompoentData( e.GetChild(0),  new MaterialAnimationFrame{ Frame=100 })[/COLOR]
    14.         }
    15.         ecb.Playback(state.EntityManager);
     
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,592
    If I understood you right, you have few options.

    Children are stored in LinkedGroup DynamicBuffer.
    So you may want to iterate through it, to get list of children.
    Thats ok, until you have more children on the entity. Then you may unnecessary iterate through other children.
    May be not an issue, if you rarely set values on such components of child entities.

    Another option is, to create on the parent component with desired entity reference.

    Other option is, if parent is not mandatory to take directly control over iterating through children, let system to handle iterating through desired children. You may want jobs, which filter such entities.

    Also, instead of using parent -> children via LinkegGroup, you can use reversed apprach.
    Child -> parent. Basically you iterate through entities which are children, and call parent with Parent Component.
    That is, if you need anything to read / set on a parent.
     
  3. bx3776

    bx3776

    Joined:
    Nov 25, 2014
    Posts:
    13

    Thank you very much for your guidance. In fact, this is a very basic problem. When I use the Prefab hierarchy, the system should automatically add LinkedEntityGroup for me, so I used a very poor method to set the value of the components in the buffer, as follows:

    Code (CSharp):
    1. var eq = state.GetEntityQuery(typeof(PlayerComponent));
    2.  
    3.         foreach (var e in eq.ToEntityArray(Allocator.Temp))
    4.         {
    5.             var buff= state.EntityManager.GetBuffer<LinkedEntityGroup>(e);
    6.             int f = random.NextInt(0, 1812 / 4);
    7.             state.EntityManager.SetComponentData(buff[1].Value, new MaterialAnimationFrame() { Frame = f });
    8.             state.EntityManager.SetComponentData(buff[2].Value, new MaterialAnimationFrame() { Frame = f });
    9.         }  
    But there is another problem: the burst compilation system prompts me that typeof(PlayerComponent) is not supported. Perhaps the api method I used to search entity is not correct?
     
  4. Spy-Master

    Spy-Master

    Joined:
    Aug 4, 2022
    Posts:
    291
    For single components, you should use the overload that takes an instance of ComponentType and pass in ComponentType.ReadOnly<PlayerComponent>() or ComponentType.ReadWrite<PlayerComponent>(). For anything more complex, you should use EntityQueryBuilder.
    The reason that typeof doesn’t work is that the typeof operator returns an instance of System.Type, which is a managed object that Burst can’t handle.
     
    Last edited: Feb 3, 2023
  5. bx3776

    bx3776

    Joined:
    Nov 25, 2014
    Posts:
    13
    Thank you very much. I replaced it with your plan.
    Code (csharp):
    1.  
    2.  public void OnUpdate(ref SystemState state)
    3.     {
    4.         var spawner= SystemAPI.GetSingleton<PlayerSpawnerComponent>();
    5.         var ecb = new EntityCommandBuffer(Unity.Collections.Allocator.Temp);
    6.         for (int i = 0; i < 1; i++)
    7.         {
    8.            var e= ecb.Instantiate(spawner.player_entity);
    9.            ecb.SetComponent<PlayerComponent>(e, new PlayerComponent() { id= i });
    10.         }
    11.         ecb.Playback(state.EntityManager);
    12.        Unity.Mathematics.Random random = new Unity.Mathematics.Random(1);
    13.        var eq = state.GetEntityQuery(ComponentType.ReadOnly<PlayerComponent>());
    14.         NativeArray<Entity> entityArray = eq.ToEntityArray(Allocator.TempJob);
    Burst works normally. That's great. But when I package it as apk and install it on my Xiaomi mobile phone, the APP always crashes and flashes back when I start it. I try to annotate every sentence in OnUpdate, and it turns out that the crash is caused by 'var spawner= SystemAPI.GetSingleton<PlayerSpawnerComponent>()' ,

    this is crash log:
    Code (CSharp):
    1. 02-03 14:12:52.231  4276  4315 E CRASH   : pid: 4276, tid: 4315, name: UnityMain  >>> com.sbin.dots <<<
    2. 02-03 14:12:52.232  4276  4315 E CRASH   :       #00 pc 0000000000158c88  /data/app/~~TlmFj-gC1lq2mOJQZnb1qg==/com.sbin.dots-m8nR6V2bj_8aMwdXtaz0cQ==/lib/arm64/lib_burst_generated.so (Unity.Entities.EntityQueryImpl.GetSingleton<PlayerSpawnerComponent>(Unity.Entities.EntityQueryImpl* this) -> PlayerSpawnerComponent_00789fe5f95acd257d6d0c29f529518b from Unity.Entities, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null+144) (BuildId: 468fba21d2b524ab)
    3. 02-03 14:12:52.232  4276  4315 E CRASH   :       #01 pc 0000000000156878  /data/app/~~TlmFj-gC1lq2mOJQZnb1qg==/com.sbin.dots-m8nR6V2bj_8aMwdXtaz0cQ==/lib/arm64/lib_burst_generated.so (PlayerSpawnerSystem.OnUpdate(PlayerSpawnerSystem* this, ref Unity.Entities.SystemState state) -> void_00789fe5f95acd257d6d0c29f529518b from Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null+268) (BuildId: 468fba21d2b524ab)
    4. 02-03 14:12:52.232  4276  4315 E CRASH   :       #02 pc 000000000012b490  /data/app/~~TlmFj-gC1lq2mOJQZnb1qg==/com.sbin.dots-m8nR6V2bj_8aMwdXtaz0cQ==/lib/arm64/lib_burst_generated.so (Unity.Entities.WorldUnmanagedImpl.Unity.Entities.UnmanagedUpdate_00001252$BurstDirectCall.Invoke(void* pSystemState) -> void_00789fe5f95acd257d6d0c29f529518b from Unity.Entities, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null+260) (BuildId: 468fba21d2b524ab)
    5. 02-03 14:12:52.232  4276  4315 E CRASH   :       #03 pc 00000000033053cc  /data/app/~~TlmFj-gC1lq2mOJQZnb1qg==/com.sbin.dots-m8nR6V2bj_8aMwdXtaz0cQ==/lib/arm64/libil2cpp.so (BuildId: f134e0bd9d6f4198)
     
    Last edited: Feb 3, 2023
  6. bx3776

    bx3776

    Joined:
    Nov 25, 2014
    Posts:
    13
    If I change GetSingleton to this way:
    Code (CSharp):
    1. PlayerSpawnerComponent spawner;
    2.        bool b= SystemAPI.TryGetSingleton(out  spawner);
    3.         //var spawner = SystemAPI.GetSingleton<PlayerSpawnerComponent>();
    4.         if (!b || spawner.player_entity== Entity.Null) return;
    the crash will no longer occur. It seems that it is a problem of timing to get the singleton component?
     
    DalamarTD7 likes this.
  7. DalamarTD7

    DalamarTD7

    Joined:
    Jan 21, 2016
    Posts:
    3
    I'm hundreds upon hundreds of hours in on Unity ECS OOP. I'm still noob but I'll share my thought on the issue.
    I'd wager, "that it is a problem of timing." I've pseudo resolved issues by using TryGetSingleton which is not the answer.
    You're probably accessing the Singleton with your System too early in the frame before it has finished processing. I suggest adding the attribute, for example, [UpdateInGroup(typeof(PhysicsSystemGroup)], to your System. There's several other standard System groups to choose from. If you go into play mode and look in the Systems tab window you'll find your System in the list or the search bar. In your case, updating your system in the Late Simulation System Group should resolve the issue if it's a matter of timing. Another option would be to require for update, End Simulation Entity Command Buffer System in the OnCreate method of your system which happens just before the Presentation System Group. If you schedule jobs using ScheduleParallel, you'll likely want to use one of the already present entity command buffers to schedule parallel jobs anyways, which will affect in which group your system updates if not specified.

    In closing, my Input system updates somewhere in the Initialization System Group, whereas my movement Systems update later in the frame somewhere in the Simulation System Group, which is after a natural sync point, and is after when my Input job dependencies complete.