Search Unity

Extending HelloCube_06 for multiple prefabs

Discussion in 'Entity Component System' started by Init33, Apr 6, 2019.

  1. Init33

    Init33

    Joined:
    Aug 30, 2017
    Posts:
    67
    In the unity Hello ECS sample 6, HelloCube_06_SpawnFromEntity the GameObject prefab is converted to an entity in the HelloSpawnerProxy script:

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using Unity.Entities;
    4. using UnityEngine;
    5.  
    6. namespace Samples.HelloCube_06
    7. {
    8.     [RequiresEntityConversion]
    9.     public class HelloSpawnerProxy : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity
    10.     {
    11.         public GameObject Prefab;
    12.         public int CountX;
    13.         public int CountY;
    14.  
    15.         // Referenced prefabs have to be declared so that the conversion system knows about them ahead of time
    16.         public void DeclareReferencedPrefabs(List<GameObject> gameObjects)
    17.         {
    18.             gameObjects.Add(Prefab);
    19.         }
    20.  
    21.         // Lets you convert the editor data representation to the entity optimal runtime representation
    22.  
    23.         public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    24.         {
    25.             var spawnerData = new HelloSpawner
    26.             {
    27.                 // The referenced prefab will be converted due to DeclareReferencedPrefabs.
    28.                 // So here we simply map the game object to an entity reference to that prefab.
    29.                 Prefab = conversionSystem.GetPrimaryEntity(Prefab),
    30.                 CountX = CountX,
    31.                 CountY = CountY
    32.             };
    33.             dstManager.AddComponentData(entity, spawnerData);
    34.         }
    35.     }
    36. }
    I am looking to extend this for multiple different prefabs and am having trouble visualising how it should come together. Since the DeclareReferencedPrefabs takes a list, I presume the intent is for multiple conversions to occur through the one script. With this in mind, I would do something like this:

    Code (CSharp):
    1. namespace Samples.HelloCube_06
    2. {
    3.     [RequiresEntityConversion]
    4.     public class HelloSpawnerProxy : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity
    5.     {
    6.         public GameObject square;
    7.         public GameObject circle;
    8.         public GameObject triangle;
    9.  
    10.         // Referenced prefabs have to be declared so that the conversion system knows about them ahead of time
    11.         public void DeclareReferencedPrefabs(List<GameObject> gameObjects)
    12.         {
    13.             gameObjects.Add(square);
    14.             gameObjects.Add(circle);
    15.             gameObjects.Add(triangle);
    16.         }
    17. ...
    However I get stuck when I get to the
    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)


    What does the "entity" variable refer to exactly? Is Convert method run once for each gameObject in the list? What if I want each gameObject prefab to have unique componentData, I couldn't use the same struct in the Convert function?

    At the moment I have both a "HelloSpawner" and "HelloSpawnerProxy" type script for each unique item in my game (2 scripts per item!) which is nonsense. Please help me make sense of this :)
     
  2. NoDumbQuestion

    NoDumbQuestion

    Joined:
    Nov 10, 2017
    Posts:
    186
    You can use AddRange to add List<GameObject> as reference in scene.
    Code (CSharp):
    1.    
    2. [RequiresEntityConversion]
    3. public class HelloSpawnerProxy : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity
    4. {
    5.     public GameObject Prefab;
    6.     public List<GameObject> prefabs;
    7.     public int CountX;
    8.     public int CountY;
    9.  
    10.     public bool isSpawn = false;
    11.  
    12.     // Referenced prefabs have to be declared so that the conversion system knows about them ahead of time
    13.     public void DeclareReferencedPrefabs(List<GameObject> gameObjects)
    14.     {
    15.         gameObjects.Add(Prefab);
    16.         gameObjects.AddRange(prefabs);
    17.     }
    18.  
    19.     // Lets you convert the editor data representation to the entity optimal runtime representation
    20.  
    21.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    22.     {
    23.         var spawnerData = new HelloSpawner
    24.         {
    25.             // The referenced prefab will be converted due to DeclareReferencedPrefabs.
    26.             // So here we simply map the game object to an entity reference to that prefab.
    27.             Prefab = conversionSystem.GetPrimaryEntity(Prefab),
    28.             CountX = CountX,
    29.             CountY = CountY
    30.         };
    31.         if(isSpawn) //Prevent spawner system from query this entity
    32.             dstManager.AddComponentData(entity, spawnerData);
    33.     }
    34. }
    35.  
    What
    DeclareReferencedPrefabs(
    do is it turn prefab into Entity "Prefab" (it show in EntityDebugger but not render or touched by any system query). Even if you declare same prefab from multiple gameobject, only 1 entity is created.

    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)

    Entity here is the new Entity created per gameobject in scene. (If it have Convert to Entity Component)
    If you add bool check before add component. You will see the Entity is created but nothing is spawned.
     
  3. Init33

    Init33

    Joined:
    Aug 30, 2017
    Posts:
    67

    I will clarify a bit since I'm not sure you understand what I am asking. Lets say I want 3 spawner entities in my system:
    • SquareSpawner
    • CircleSpawner
    • TriangleSpawner
    I want them labelled as such since I want to spawn a specific thing (square, circle, triangle) when I click a button. So in another system I could do something like:
    Code (CSharp):
    1.     EntityQuery circleSpawners;
    2.     circleSpawners = GetEntityQuery(typeof(CircleSpawner));
    3. ...
    and then do tasks specifically with spawning circles.

    In my project scene I have a GameObject with a script on it where I put all my shape prefabs (square, circle, triangle) which takes each prefab and converts the first one to an entity with SquareSpawner component, the second one to an entitiy with CircleSpawner component, and so on.

    In the HelloSpawner script, there is only one Convert function for the multiple prefabs that I can give to the declareReferencedPrefabs. In that Convert function, the ComponentData struct that is given to each entity is the same. I want different ComponentData given to the first, second, and third prefabs individually.

    Here is some psuedocode to outline what I'm talking about a bit more. Keep in mind this code is syntactically incorrect but I just wanted to hone in on the problem.

    Code (CSharp):
    1. public class HelloSpawnerProxy : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity
    2.     {
    3.         public GameObject square;
    4.         public GameObject circle;
    5.         public GameObject triangle;
    6.  
    7.         // Referenced prefabs have to be declared so that the conversion system knows about them ahead of time
    8.         public void DeclareReferencedPrefabs(List<GameObject> gameObjects)
    9.         {
    10.             gameObjects.Add(square);
    11.             gameObjects.Add(circle);
    12.             gameObjects.Add(triangle);
    13.         }
    14.  
    15.         // Lets you convert the editor data representation to the entity optimal runtime representation
    16.  
    17.         public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    18.         {
    19.             var squareSpawnerData = new SquareSpawner
    20.             {
    21.                 Prefab = conversionSystem.GetPrimaryEntity(square),
    22.             };
    23.  
    24.             var circleSpawnerData = new CirlceSpawner
    25.             {
    26.                 Prefab = conversionSystem.GetPrimaryEntity(circle),
    27.             };
    28.  
    29.             var triangleSpawnerData = new TriangleSpawner
    30.             {
    31.                 Prefab = conversionSystem.GetPrimaryEntity(triangle),
    32.             };
    33.  
    34.             // if its the square
    35.             dstManager.AddComponentData(entity, squareSpawnerData);
    36.             // if its the circle
    37.             dstManager.AddComponentData(entity, circleSpawnerData);
    38.             // if its the triangle
    39.             dstManager.AddComponentData(entity, triangleSpawnerData);
    40.         }
    41.     }
     
  4. NoDumbQuestion

    NoDumbQuestion

    Joined:
    Nov 10, 2017
    Posts:
    186
    You mean gameobject selection which kind of spawner you want? Add Enum
    Code (CSharp):
    1.  
    2. public class HelloSpawnerProxy : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity
    3. {
    4.     public GameObject square;
    5.     public GameObject circle;
    6.     public GameObject triangle;
    7.     public SpawnerType spawnType;
    8.    
    9.     public enum SpawnerType
    10.     {
    11.         None,
    12.         Square,
    13.         Triangle,
    14.         Circle
    15.     }
    16.  
    17.     // Referenced prefabs have to be declared so that the conversion system knows about them ahead of time
    18.     public void DeclareReferencedPrefabs(List<GameObject> gameObjects)
    19.     {
    20.         gameObjects.Add(square);
    21.         gameObjects.Add(circle);
    22.         gameObjects.Add(triangle);
    23.     }
    24.    
    25.     // Lets you convert the editor data representation to the entity optimal runtime representation
    26.    
    27.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    28.     {
    29.         var squareSpawnerData = new SquareSpawner
    30.         {
    31.             Prefab = conversionSystem.GetPrimaryEntity(square),
    32.         };
    33.    
    34.         var circleSpawnerData = new CirlceSpawner
    35.         {
    36.             Prefab = conversionSystem.GetPrimaryEntity(circle),
    37.         };
    38.    
    39.         var triangleSpawnerData = new TriangleSpawner
    40.         {
    41.             Prefab = conversionSystem.GetPrimaryEntity(triangle),
    42.         };
    43.  
    44.         switch (spawnType) {
    45.         case SpawnerType.Square:
    46.             // if its the square
    47.             dstManager.AddComponentData(entity, squareSpawnerData);
    48.             break;
    49.         case SpawnerType.Triangle:
    50.             // if its the triangle
    51.             dstManager.AddComponentData(entity, triangleSpawnerData);
    52.             break;
    53.         case SpawnerType.Circle:
    54.             // if its the circle
    55.             dstManager.AddComponentData(entity, circleSpawnerData);
    56.             break;
    57.         default:
    58.             throw new ArgumentOutOfRangeException();
    59.         }
    60.     }
    61. }
    62.  
     
  5. Init33

    Init33

    Joined:
    Aug 30, 2017
    Posts:
    67
    I think I have come up with a better approach. My key goal was to make a concise work environment from the scene view to reduce clutter. I have made a spawner ComponentData type called ShapeSpawner, which has 3 prefabs (square, circle, triangle). Now I can easily pass my ShapeSpawner around if I want to spawn a shape, and call on the correct prefab by name:


    Code (CSharp):
    1. public class ShapesSpawnerProxy : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity
    2. {
    3.     public GameObject square;
    4.     public GameObject circle;
    5.     public GameObject triangle;
    6.  
    7.     // Referenced prefabs have to be declared so that the conversion system knows about them ahead of time
    8.     public void DeclareReferencedPrefabs(List<GameObject> gameObjects)
    9.     {
    10.         gameObjects.Add(square);
    11.         gameObjects.Add(circle);
    12.         gameObjects.Add(triangle);
    13.     }
    14.  
    15.     // Lets you convert the editor data representation to the entity optimal runtime representation
    16.  
    17.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    18.     {
    19.         var spawnerData = new ShapeSpawner
    20.         {
    21.            square = conversionSystem.GetPrimaryEntity(square),
    22.            circle = conversionSystem.GetPrimaryEntity(circle),
    23.            triangle = conversionSystem.GetPrimaryEntity(triangle),
    24.         };
    25.         dstManager.AddComponentData(entity, spawnerData);
    26.     }
    27. }
    28.  
    29. public struct ShapeSpawner : IComponentData
    30. {
    31.     public Entity square;
    32.     public Entity circle;
    33.     public Entity triangle;
    34. }
    Now I can control how much granularity I want with my spawners. If a system only needs to spawn shapes, I can give it my ShapeSpawner. Another system might need projectiles, so I can give it my ProjectilesSpawner... etc. It basically becomes a library of entity prefabs that are injectable.
     
  6. dansyrotyn

    dansyrotyn

    Joined:
    Oct 16, 2012
    Posts:
    15
    Is it possible to make it work not with prefabs, but game objects in scene?