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. Dismiss Notice

Question Injection from GameObject Context into instantiated Scriptable Object

Discussion in 'Scripting' started by a-t-hellboy, Sep 7, 2023.

  1. a-t-hellboy

    a-t-hellboy

    Joined:
    Dec 6, 2013
    Posts:
    180
    I have a question about combination of factory and subcontainer, probably for the issue I already have.

    I have a few scriptable object which are instantiated at the beginning of the game based on which one is selected. Also the gameObject which instantiate them has GameObject Context and some classes are bound there. Which one of those classes should be injected into these scriptable objects.

    The issue I have that class which is bound in GameObject Context and its MonoInstaller is not injected into my scriptable objects constructor. (btw, that gameObject which I said above and instantiate these scriptable object is instantiated at the beginning of the game by another gameObject which is in the scene hierarchey)

    After a little investigation I find out probably I should use combination of BindFactory and FromSubContainerResolve but I can't figure out how to fit that in my current system.

    My factory implementation is in this way: (Though I'm not sure if it is better to work in this way or it is better to use PlaceholderFactory)

    Code (CSharp):
    1. public class ZenjectResourceFactory : IResourceFactory
    2. {
    3.    private readonly DiContainer _container;
    4.  
    5.    public ZenjectResourceFactory(DiContainer container)
    6.    {
    7.        _container = container;
    8.    }
    9.  
    10.    public Object Instantiate(Object [USER=646077]@object[/USER])
    11.    {
    12.        Object instance = Object.Instantiate([USER=646077]@object[/USER]);
    13.        _container.Inject(instance);
    14.        return instance;
    15.    }
    16.  
    17.    public Transform Instantiate(Transform transform)
    18.    {
    19.        Transform obj = _container.InstantiatePrefab(transform).transform;
    20.        return obj;
    21.    }
    22.  
    23.    public Transform Instantiate(Transform transform, Transform parent)
    24.    {
    25.        Transform obj = _container.InstantiatePrefab(transform, parent).transform;
    26.        return obj;
    27.    }
    28.  
    29.    public Transform Instantiate(Transform transform, Vector3 position)
    30.    {
    31.        Transform obj = _container.InstantiatePrefab(transform).transform;
    32.        obj.transform.position = position;
    33.        return obj;
    34.    }
    35.  
    36.    public Transform Instantiate(Transform transform, Vector3 position, Transform parent)
    37.    {
    38.        Transform obj = _container.InstantiatePrefab(transform, parent).transform;
    39.        obj.transform.position = position;
    40.        return obj;
    41.    }
    42.  
    43.    public Transform Instantiate(Transform transform, Vector3 position, Quaternion rotation, Transform parent)
    44.    {
    45.        Transform obj = _container.InstantiatePrefab(transform, parent).transform;
    46.        obj.transform.position = position;
    47.        obj.transform.rotation = rotation;
    48.        return obj;
    49.    }
    50. }
     
  2. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    Man after reading that, I'm glad I don't use Scriptable Objects... Although I can already hear Spiney on his war path, I was never here, you didn't hear anything from me... "These are not the droids you are looking for"...
     
  3. a-t-hellboy

    a-t-hellboy

    Joined:
    Dec 6, 2013
    Posts:
    180
    Actually came back to one of my projects after a few years (Even I've not touched Unity for a few years too). I still like Scriptable Objects but I think I'm not fan of Dependency injection anymore but I need it for refactoing some code on my old project. Also look like Zenject/Extenject community is dead so pretty hard to find an answer.
    btw, the issue I already have is not because of Scriptable Objects and it is because of dependency injection. Because actually I can easily inject what I want after instantiation directly but because I already use this framework I want to make it in that way. (Because of this I'm not fan of depdency injection at least Zenject and in Unity anymore, things are get very complicated in this way but prbably I'm wrong, really don't want to discuss about pros and cons of depedency injection)
     
  4. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    All jokes aside, why do you wrap your methods in such a way? Instantiate is meant for creating a gameObject, you are declaring half of these things as transforms. So I am a bit confused, what is the actual goal here?
     
  5. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    can confirm, old ways, let that go. :)
     
  6. a-t-hellboy

    a-t-hellboy

    Joined:
    Dec 6, 2013
    Posts:
    180
    Yup, actually I shouldn't paste my entire code there. I just use
    public Object Instantiate
    for instantiating Scriptable Objects so probably I should add something there or entirely change my factory approach.
     
  7. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    it's potayto/potahto... You just needs things simplified, what is it you want to happen, and what's the best way(per project) for it to happen? There is always several ways to do the same thing.. So whether you follow SOLID principals, or you just do what needs done, it doesn't matter.. As long as you understand it, who cares who doesn't..

    But again I ask, are you referring to Object Pooling, or is this more meant for Resource pulling? What is your goal?
     
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Not sure it is legal to ever make a constructor for ScriptableObject or MonoBehaviour, or really any class under Unity.

    Also, none of the above could ever be called from a field initializer in a MB/SO because those are called on a loading thread, and most of the Unity API is off-limits anywhere except the main thread.

    Meanwhile, I like this pattern:

    Factory Pattern in lieu of AddComponent (for timing and dependency correctness):

    https://gist.github.com/kurtdekker/5dbd1d30890c3905adddf4e7ba2b8580

    It has the important advantage that it recognizes Unity is special in constructor land.
     
  9. a-t-hellboy

    a-t-hellboy

    Joined:
    Dec 6, 2013
    Posts:
    180
    Yup, you are totally right. By constructor in Scriptable Object I mean, my Constructor function. (One of the reasons which DI is not suitable for Unity because of MonoBehaviour inheritance imo)
    Actually Zenject uses [Inject] attribute above the method for method injection.
    But I don't think so if my issues is relevant to the link you send here. My factory method is alongside use of Zenject.


    Code (CSharp):
    1. [Inject]
    2. public void Construct(CharacterPowerupContext context)
    3. {
    4.     _context = context;
    5. }
     
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Relevant however is why you would ever use Zenject when Unity's built-in dependency injection works perfectly 100% of the time and plays well with everything you will ever integrate from the Asset Store or any "normal" Unity site.

    The Unity dependency injection I'm talking about is of course the Scene / Prefab system. It really works perfectly in all cases, and always considers so much of your problem space and details of timing.

    Not only that, it is 100% data driven! YES! You can change the outcome of your running code trivially from a constructor standpoint simply by changing Scene / Prefab data. Addressables / Asset Bundles let you remote-control your running game robustly, more robustly than any system you could cobble together.

    Why would you ever give that up unless you just like writing boilerplate code?
     
    a-t-hellboy likes this.
  11. a-t-hellboy

    a-t-hellboy

    Joined:
    Dec 6, 2013
    Posts:
    180
    Yup
    Yup, you are right and it totally makes sense. I don't really want to discuss about it and I like the way you describe that.
    But tbh I just want to overcome this issue in Zenject way instead of removing Zenject from my project or even just use that for SceneContex or ProjectContext stuff.
     
  12. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    In his defense he said:
    So is well understood he's using old methods, and having an issue with new ways..

    Can agree, 100% ^, best way to go..

    I feel like my methods are being attacked here, but yes, why would one want "to-the-point" code... it's un-thinkable! lol, luv-ya Kurt!

    But to be fair, Kurt and Spiney definitely have that realm of logic handled far better than I can, I'm more to the point kinda' guy.. So, I'll back off, my bad.
     
    a-t-hellboy likes this.
  13. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    Kurt, WideEye, you two really need to try and actually answer the question in the thread sometime.

    Would moving to the use of plain C# classes work here? Scriptable Objects are great but when it comes to instantiating them, I always ask, "Isn't it better to use regular C# classes?" for such a purpose?

    In particularly they aren't beholden to the same managed lifestyle of Unity objects, and I imagine would probably play better with dependency injection

    You can still use SO's, but I find they're much better when used as factories for these plain C# objects.
     
    wideeyenow_unity likes this.