Search Unity

Possible to reference specific child without adding GameObjectEntity to prefab?

Discussion in 'Entity Component System' started by MostHated, Aug 23, 2019.

  1. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,235
    Hey all,
    I am running into a bit of an issue with my vehicles. I have an IComponentData on each of the wheels for rotation and speed, but that was all I had on the prefab as I was manually adding and settings things as needed when I spawned it. I was adding the wheels ahead of time because when I convert the whole thing there isn't really a way that I know of to reference them without having the IComponentData on it head of time.

    Everything works well on it minus when I first start the game, because I have a list of different vehicles that the spawning system uses to pick a random one, the fact that the wheels have the script on them and they are in a list in the scene it causes them to become active entities when I am not ready for them yet.
    (I tried to see if I loaded and added the prefab at runtime if it would make a difference doing the following, but it didn't, it had the same result)
    Code (CSharp):
    1. var vehicle = (GameObject)AssetDatabase.LoadAssetAtPath("Assets/_instance.id/_ECS/scripts/vehicle/Models/SM_Veh_Car_Sports_ECS_Test.prefab", typeof(GameObject));
    2. passengerVehicle.Add(vehicle);
    So the question is really two things, is it possible to simply have my prefab without the wheels components on them yet and somehow, (perhaps with a specific hierarchy setup? Right now it's a single parent entity, which is the body, then wheels and such are all just children of that,) be able to identify and reference the wheels to be able to add the component on them at runtime?

    The second is, if that won't work, is there some other type of thing I can add to the wheels that won't automatically add and not let me remove a GameObjectEntity, so that they do not become active entities before I am ready to build and instantiate the rest of the vehicle?

    Thanks,
    -MH
     
    Last edited: Aug 23, 2019
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    Why are you trying to add the components at runtime rather than setting them after instantiating the prefab?
     
  3. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,235
    Well, I had the components on there from the start and I was just setting them at the point of instantiation originally. As I explained above, in because doing so it was causing those items to be active entities before I was ready to create and add the vehicles.

    When I tried to create a process to remove those ones that showed up at the start it just ended up saying "Entity could not be found" or something along those lines, even though I could clearly see the vehicle and it's child entities at the very top of the list as they were added straight away because the vehicle prefab was in a List<GameObject> so the spawning system could spawn random vehicles out of the list as seen below.



    The vehicle in the "Passenger Vehicle" list, when it has all the components on it before hand, when I start the game, because having IComponentData on them, it also adds the GameObjectEntity, which then causes whatever vehicles are in the list to create entities before I am wanting them in game, and it has not let me remove them.

    I was going to use the below to add a few things to each one, then in a job looking for the SetupTag was going to do the rest, such as handling path generation and all that.

    Code (CSharp):
    1.                 if (currentCount < maxVehicles)
    2.                 {
    3.                     spawn = maxVehicles - currentCount;
    4.                     vehicleEntities = new NativeArray<Entity>(spawn, Allocator.TempJob);
    5.                     for (int i = 0; i < spawn; i++)
    6.                     {
    7.                         vehicleEntities[i] = entityManager.Instantiate(vehicleEntity);
    8.                         vehicleTotal++;
    9.                         entityManager.AddComponentData(vehicleEntities[i], new VehicleTag());
    10.                         entityManager.AddComponentData(vehicleEntities[i], new VehicleSetupTag());
    11.                         entityManager.AddComponentData(vehicleEntities[i], new VehicleData { vehicleId = vehicleTotal });
    12.                         entityManager.AddComponentData(vehicleEntities[i], new VehicleSpeed { speed = RndVehicleSpeed() });
    13. #if UNITY_EDITOR
    14.                         entityManager.SetName(vehicleEntities[i], $"Vehicle{vehicleTotal}");
    15. #endif
    16.                     }
    17.                     Logwin.Log("Spawn Amount", spawn, "Vehicles");
    18.                     vehicleEntities.Dispose();
    19.                 }
    The above was a bit different before and most of the setting of the components was done in a job, but so far any which way I seem to try it, I always end up with a random vehicle's entities being created before I am ready because of the fact they were in the list.

    All in all, everything I have setup works quite well, minus it creating those random ones at the start, so I am just trying to figure out a way to adjust my creation process to eliminate them. Either by constructing the vehicle in such a way that the components do not get added until I am ready for them to be added by trying to locate the wheel entities by some other means.

    If that doesn't work, perhaps not having the vehicle be a complete prefab and having the wheels be separate, creating them and adding the wheel component to them, then adding them to the rest of the vehicle, I suppose.
     
    Last edited: Aug 23, 2019
  4. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    Entities with the prefab component attached don't show up in normal queries.
     
  5. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,235
    Oh? So perhaps I was trying to locate and remove them incorrectly?

    At first I had a VehicleData component on the parent object of the prefab (which housed waypoint information, a vehicleId, etc), the rogue vehicle then, of course, had a VehicleData on it and since it was created before the actual setup process it's vehicleId in vehicleData was set to just a default 0, so in my removal process I set it to also look for an entity whos vehicleid == 0 and remove it. That was using IJobForEachWithEntity<VehicleData>, but that came back with an error saying Entity could not be found as soon as it hit that particular one.

    I tried to get a reference to that particular entity a few ways, as well as GetEntityQuery but no matter what way I tried, each time it came back saying it could not be found when it hit that one.

    EDIT --

    This was what I had on the vehicle -
    Code (CSharp):
    1. namespace instance.id.ECS
    2. {
    3.     //    [RequiresEntityConversion]
    4.     [DisallowMultipleComponent]
    5.     public class VehicleSpawnProxy : MonoBehaviour, IConvertGameObjectToEntity
    6.     {
    7.         public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    8.         {
    9.             var vehicleTag = new VehicleTag();
    10.             var vehicleData = new VehicleData();
    11.             var vehicleSpeed = new VehicleSpeed();
    12.             dstManager.AddComponentData(entity, vehicleTag);
    13.             dstManager.AddComponentData(entity, vehicleData);
    14.             dstManager.AddComponentData(entity, vehicleSpeed);
    15.         }
    16.     }
    17. }
    Then I was using this to get one of the vehicles:

    Code (CSharp):
    1. var randVehicle = UnityEngine.Random.Range(0, VehicleController.instance.passengerVehicle.Count);
    2.             vehicleEntity = GameObjectConversionUtility.ConvertGameObjectHierarchy(VehicleController.instance.passengerVehicle[randVehicle], World.Active);
    Then when I was ready I was using this to get the ball rolling with the rest of the setup: (which was from the code I posed in the previous post)

    vehicleEntities = entityManager.Instantiate(vehicleEntity);
    Code (CSharp):
    1. vehicleEntities[i] = entityManager.Instantiate(vehicleEntity);
    Because I was trying different things recently the AddComponentData was SetComponentData in the code of the previous post in the applicable places.
     
    Last edited: Aug 23, 2019
  6. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    Is this GameObject just a GameObject in the scene or a prefab referenced by an IDeclareReferencedPrefabs?
     
  7. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,235
    Well, I suppose technically it ends up being a random gameobject in the scene because of the fact that it is in a list on a gameobject that is in the scene.

    At first, the conversion code in my previous post was what I had on the vehicle, but then since it was technically a gameobject in the scene, I tried this out to test and see if it made a difference by creating a VehicleProxy object and adding this to it, which I then took the vehicle, removed the original script from it (keeping the one on the wheels though) and referenced the prefab on the VehicleProxy and added that to the list, but the outcome was the same, still a random broken vehicle at the start:

    Code (CSharp):
    1. namespace instance.id.ECS
    2. {
    3.     [RequiresEntityConversion]
    4.     [DisallowMultipleComponent]
    5.     public class VehicleSpawnProxy2 : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity
    6.     {
    7.         public GameObject Prefab;
    8.      
    9.         public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs)
    10.         {
    11.             referencedPrefabs.Add(Prefab);
    12.         }
    13.  
    14.         public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    15.         {
    16.             var vehicleEntity = new VehicleEntity
    17.             {
    18.                 entity = conversionSystem.GetPrimaryEntity(Prefab)
    19.             };
    20.             var vehicleTag = new VehicleTag();
    21.             var vehicleData = new VehicleData();
    22.             var vehicleSpeed = new VehicleSpeed();
    23.             dstManager.AddComponentData(entity, vehicleEntity);
    24.             dstManager.AddComponentData(entity, vehicleTag);
    25.             dstManager.AddComponentData(entity, vehicleData);
    26.             dstManager.AddComponentData(entity, vehicleSpeed);
    27.         }
    28.     }
    29. }
     
  8. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    I am having a difficult time following what you are doing and what you are seeing. You may need to show some pictures of your hierarchy setup and the resulting entities you are seeing.
     
  9. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,235
    I can certainly understand. Unfortunately, I have to get to bed right now but I will try and get some pics and perhaps a video clip to show what is happening tomorrow morning. I definitely appreciate you taking the time to have a listen. Have a good one.
     
  10. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,235
    Hey there @DreamingImLatios, just wanted to give a quick update. I decided to try something out a bit differently and it looks like it solved my issue for the most part. I believe it may not be the most effecient, but it is a step in the right direction as I have no more rogue vehicle.

    I believe where my issue stemmed from the fact that when the waypoints and other things were setup and ready for vehicles to be spawned, that called a SetupComplete() method in which I was passing in the List<GameObject> which contained the vehicles.

    At which point I was using:
    Code (CSharp):
    1. var randVehicle = UnityEngine.Random.Range(0, VehicleController.instance.passengerVehicle.Count);
    2. vehicleEntity = GameObjectConversionUtility.ConvertGameObjectHierarchy(VehicleController.instance.passengerVehicle[randVehicle].prefab, World.Active);
    Later on when I went to spawn the vehicles I was using:

    Code (CSharp):
    1. for (int i = 0; i < spawn; i++)
    2. {
    3.     vehicleEntities[i] = entityManager.Instantiate(vehicleEntity);
    4. }
    It seems it was my bad as I thought that simply doing the game object conversion and storing it counted as creating an "entity prefab" in which you could use later to spawn entities, which I had seen mentioned somewhere before. I was under the impression that it would not create any active entities yet until you used that stored conversion and instantiated it, but it seems that is not the case.

    So what I just tried to do now was, when the condition is met in which vehicles are to be created, I simply called the gameobject conversion once before my loop, create however many need to be created, then did entityManager.DestroyEntity(vehicleEntity);
    I had my proper vehicle spawned and no extra broken vehicles.

    Again, I appreciate your assistance yesterday, even though my issue was not exactly clear, the questions you asked ended up having me revisit the thing that was the problem anyways, so cheers to that.
     
  11. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    If you just did EntityManager.AddComponent(vehicleEntity, new Prefab {}) right after the ConvertGameObjectHierarchy you would get the initial result based on your initial assumption.
     
  12. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,235
    EDIT -- Looks like I have everything squared away. Ended up creating a pool and doing some other changes and optimizations and things are working great now.

    Hmm.. this is curious. I tried to do it with what you mentioned above, but kept getting an error in IDE.


    So I tried this way first:
    Code (CSharp):
    1. vehicleEntity = GameObjectConversionUtility.ConvertGameObjectHierarchy(vehicleProx.prefab, World.Active);
    2. entityManager.AddComponent<Prefab>(vehicleEntity);
    That sort of worked. Nothing showed up right away, but as soon as I instantiated the first vehicle, the rogue entities *then* showed up. So I replaced that with this:

    Code (CSharp):
    1. vehicleEntity = GameObjectConversionUtility.ConvertGameObjectHierarchy(vehicleProx.prefab, World.Active);
    2. entityManager.AddComponent(vehicleEntity, typeof(Prefab));
    But then they showed up straight away as they were before.

    I could remove vehicleEntity as I proposed in my prior post, but that would defeat the purpose of trying to keep an entity prefab around as it would get rid of the rogue entities, but then not be available anymore for spawning more. Though, it's not much of an entity prefab if it becomes and remains active but broken.

    I am trying to see what other information I can find on exactly how the prefab portion is supposed to work.

    All in all, it is not a big deal, doing it the way I had figured out that works without extra entities is fine for now. I am mostly just learning and building a demo scene. Nothing really important.
     
    Last edited: Aug 25, 2019