Search Unity

GetComponentObject returns are null? (Or some other related problem?)

Discussion in 'Entity Component System' started by NotaNaN, Feb 16, 2019.

?

Is it...

Poll closed Feb 16, 2019.
  1. Problem 1?

    0 vote(s)
    0.0%
  2. Problem 2?

    0 vote(s)
    0.0%
  3. Problem 3?

    0 vote(s)
    0.0%
  4. An unlisted problem?

    0 vote(s)
    0.0%
  5. A personal problem?

    1 vote(s)
    100.0%
  6. All of the above?

    0 vote(s)
    0.0%
Multiple votes are allowed.
  1. NotaNaN

    NotaNaN

    Joined:
    Dec 14, 2018
    Posts:
    325
    I seem to be having a problem where whenever i try to get a reference to a MonoBehavioural Component (Such as a Rigidbody using EntityManager.GetComponentObject) it returns null... Or more specifically the returned component is null... Whichever is the case this problem has been driving me around the bend and i flat out don't know how to fix it. So if you guys cold hold my hand for this one it'd be greatly appreciated!

    The code I'm using to test this is as follows:
    Code (CSharp):
    1. var tempManager = World.Active.GetOrCreateManager<EntityManager>();
    2.  
    3. EntityArchetype rigidArchetype = tempManager.CreateArchetype
    4.     (typeof(Position), typeof(Rotation), typeof(Scale),
    5.      typeof(SpriteRenderer), typeof(BoxCollider2D), typeof(Rigidbody2D));
    6.  
    7. var createdEntity = tempManager.CreateEntity(rigidArchetype);
    8. Rigidbody2D rigidbody2D = tempManager.GetComponentObject<Rigidbody2D>(createdEntity);
    9. Debug.Log(rigidbody2D);

    When ran, the Debug.Log says that the Rigidbody2D is null.

    Now I've been thinking this over, and if i haven't missed anything blatantly stupid the problem could be one of three issues:
    1. The Rigidbody2D within the archetype itself is null. (Thus making any reference grabs null as well).
    2. When GetComponentObject attempts to grab a reference the component doesn't exist on the entity yet. (Yeah, i know, it sounds absurd... But if there is any kind of weird delay for archetype creation then that might be the problem)
    And 3. I'm TOTALLY using GetComponentObject wrong.

    In hopes to get around suggested "problem 2" I've already tried to use EntityManager.AddComponent, but it didn't do anything different (except be less efficient) and it won't let me attempt to hold a reference to the object as the function returns void. I've also tried giving up -- which did work, but it didn't exactly give the desired results... So i think that is off the table.

    If anybody has insight into this problem that they'd like to share or would just like to throw in their two cents, please do. I admittedly have been banging my head against this problem for far to long now and just want it over with.
     
    Last edited: Feb 16, 2019
  2. thelebaron

    thelebaron

    Joined:
    Jun 2, 2013
    Posts:
    857
    im assuming you didnt add your component the old way, so something like
    Code (CSharp):
    1. var rigidbody2D = tempManager.GetComponentObject<Transform>(createdEntity).AddComponent<Rigidbody2d>();
     
  3. NotaNaN

    NotaNaN

    Joined:
    Dec 14, 2018
    Posts:
    325
    Hmm... "Old way"? I've never seen or even heard of this "Old way", but i like it! Will try this as soon as possible.

    EDIT: I attempted to do what you suggested but all i got was red squigglies beneath the .AddComponent<Rigidbody2D>();
    Is there a special using directive that I'm missing to allow the use of the AddComponent function in that location? (It says there is no extension method for AddComponent in Transform).
    I'll keep fiddling around with it and see if i can get what you're supposing to work.

    EDIT 2: Did you mean to use GetComponent instead? I haven't tested it yet, but i might be able to get the info i need by replacing AddComponent with it.

    EDIT 3: No cigar sadly... Transform is just as null as the Rigidbody2D (and yes, i added it to the archetype)... So despite your helpful ideas the problem still seems to skirt back to the original one... Why are the components null when added via typeof()?
     
    Last edited: Feb 16, 2019
  4. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    You could write your own create entity from EntityArchetype like this:
    Code (CSharp):
    1.   public Entity CreateEntity(EntityManager manager, EntityArchetype entityArchetype) {
    2.     var goe = new GameObject().AddComponent<GameObjectEntity>();
    3.     foreach (var type in entityArchetype.ComponentTypes) {
    4.       if (type.AccessModeType != ComponentType.AccessMode.Subtractive && type != typeof(Entity)) {
    5.         if (type.IsZeroSized)
    6.           goe.gameObject.AddComponent(type.GetManagedType());
    7.         else
    8.           manager.AddComponent(goe.Entity, type);
    9.       }
    10.     }
    11.     return goe.Entity;
    12.   }
    Anyway when you try to get the componet object using tempManager.GetComponentObject<Rigidbody2D> you will get ArgumentException: The component has not been added to the entity.

    Anyway you should rather create a system and query those components from there.
     
    NotaNaN likes this.
  5. thelebaron

    thelebaron

    Joined:
    Jun 2, 2013
    Posts:
    857
    i just realised there may not even be a gameobject for the entity you made. I am assuming the rigidbody2d and boxcollider are the old style monobehaviours and not your own ComponentData right?
     
  6. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    This will work but again usesystems instead :p
    Code (CSharp):
    1. public class Behaviour : MonoBehaviour {
    2.  
    3.   void Start() {
    4.  
    5.     var tempManager = World.Active.GetOrCreateManager<EntityManager>();
    6.  
    7.     EntityArchetype rigidArchetype = tempManager.CreateArchetype
    8.         (typeof(Position), typeof(Rotation), typeof(Scale),
    9.          typeof(SpriteRenderer), typeof(BoxCollider2D), typeof(Rigidbody2D));
    10.  
    11.     var goe = CreateEntity(tempManager, rigidArchetype);
    12.     var rigidbody2D = goe.GetComponent<Rigidbody2D>();
    13.     Debug.Log(rigidbody2D);
    14.   }
    15.  
    16.   public GameObjectEntity CreateEntity(EntityManager manager, EntityArchetype entityArchetype) {
    17.     var goe = new GameObject().AddComponent<GameObjectEntity>();
    18.     foreach (var type in entityArchetype.ComponentTypes) {
    19.       if (type.AccessModeType != ComponentType.AccessMode.Subtractive && type != typeof(Entity)) {
    20.         if (type.IsZeroSized)
    21.           goe.gameObject.AddComponent(type.GetManagedType());
    22.         else
    23.           manager.AddComponent(goe.Entity, type);
    24.       }
    25.     }
    26.     return goe;
    27.   }
    28. }
     
    NotaNaN likes this.
  7. dstilwagen

    dstilwagen

    Joined:
    Mar 14, 2018
    Posts:
    36
    I think your misunderstanding how to use MonoBehaviour components with ECS, Just like how you can't directly attach an ECS Component struct to a GameObject you need a wrapper, and you can't attach MonoBehaviour components directly to an Entity. This is where the GameObjectEntity component comes in, by attaching that component to a GameObject you are linking the two. This allows you to use the Entity to query for components on the linked GameObject using GetComponentObject(). Creating an entity from an archetype with MonoBehaviour components or adding them using AddComponent() doesn't create an actual instance of that component thus making it always null.

    For completeness I will say that you can use reflection to access a function called SetComponentObject() that will allow you to do what you want. If you are interested in doing that check out tertle's post here https://forum.unity.com/threads/pure-ecs-and-gameobjects.578713/#post-3859612 and the whole post might be worth reading.
     
    NotaNaN likes this.
  8. NotaNaN

    NotaNaN

    Joined:
    Dec 14, 2018
    Posts:
    325
    Ah, that all makes sense... The version of the components on the entity are hollow variations of the corresponding GameObject components so that the entity can iterate through them and get the "real" components (the ones that are on the GameObject) using reflection (or some subset of it). MAN, I wish i had this information before! This really clears things up for me about why we need GameObjects for our Hybrid Entities.

    Thank you to everyone who helped me out with this, Especially @GilCat and @dstilwagen . I believe all of this information is more than enough for me to get my heading, and i will definitely consult all of you if i have any more problems that i can't get over by myself.

    Again, thank you both!

    (I will also update my previous thread: https://forum.unity.com/threads/exa...en-a-hybrid-entity-and-its-gameobject.629938/ with a link to GilCat's answer, as his reply also answers that threads questions correctly as well).
     
    Last edited: Feb 16, 2019