Search Unity

Initializing a prefab via code

Discussion in 'Prefabs' started by kstrous, May 31, 2022.

  1. kstrous

    kstrous

    Joined:
    Oct 26, 2021
    Posts:
    7
    I'm working on an inventory and I'm trying to reinstantiate my in game item when I remove it from the inventory. My in game items are built from a simple prefab with a transform, a light, and a reference to the item it's supposed to be.

    My problem right now seems to be that I can't properly initialize the prefab via code. At the top of my script I wrote "public GameObject inGameItemPrefab;" , which I use to drag in my prefab via the editor.

    Then, when I try to instantiate the variable:
    inGameItemPrefab.GetComponent<RectTransform>().localPosition = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>().position;
    Instantiate(inGameItemPrefab, transform);

    It always gives a null error, I've done some testing and any mention to ingameitemprefab returns null, so it's not coming from findwithtag or something like that.

    So what would be the proper way to initialize the prefab, is that even possible?

    My backup would be to create a gameobject from scratch and add all the components to it, but that would be a LOT more code as I'd have to manually set the 2d light setting and whatnot.
     
  2. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    602
    Don't modify properties of the the prefab. Modify the properties of the instance object returned by Instantiate method. That should shouldn't case the null error. At least for the part of code you showed it's hard to tell which part is causing the error. Split the code in smaller chunks that way it's clearer where the error is coming from. Expect copy pasted rant about hating yourself from Kurt. I don't always agree with his threshold for what's too much, but in this case you are doing way too much in single line and it is preventing you from easily identifying the source of error.

    From your post it's unclear if you properly understand the difference between prefab and the instance of prefab. I have seen plenty of cases where beginners are calling later as the first one, which in can easily result in confusion during communication with others.

    Just to be clear typical workflow with prefabs is something like this:
    • create prefab in editor
    • (a) create some instance of prefab within scene by dragging the prefab from project view to scene
    • (b) Crate a field in MonoBehavior for storing reference to prefab
    • (b) in editor drag the prefab (the .prefab file from project tab not an object from scene) to the new field in inspector
    • (b) At runtime have something like this

    Code (CSharp):
    1. class BarSpawner : MonoBehavior
    2. {
    3.    public GameObject barPrefab; // assigned in edit mode
    4.    GameObject barInstance;
    5.    void SpawnBar()
    6.    {
    7.       // Create prefab instance and save in variable for later use.
    8.       // Can also be stored in local variable instead of class field if you won't need to access later
    9.       // There are few variations of instantiate with more arguments
    10.       /// for specifying position or parent without having to do it later in separate steps
    11.        barInstance = Instantiate(barPrefab);
    12.  
    13.  
    14.  
    15.        // modify properties or call methods for newly created prefab instance
    16.        barInstance.GetComponent<Bar>().abc = 123;
    17.    }
    18. }
    If you know that prefab will have some component and you will rarely access rest of the components, you may do something like this, saving you some GetComponent calls and reducing the chance of making mistakes by assigning wrong object.

    Code (CSharp):
    1. class BarSpawner : MonoBehavior
    2. {
    3.    public Bar barPrefab; // assigned in edit mode
    4.    Bar barInstance;
    5.    void SpawnBar()
    6.    {
    7.        barInstance = Instantiate(barPrefab);
    8.        barInstance.abc = 123;
    9.    }
    10. }

    Some additional suspicious aspects of your code that might sooner or later cause you issues or are already confusing you causing you to make wrong conclusions:
    • be very careful when mixing RectTransform stuff with regular transform. RectTransform is usually used for canvas stuff which have completely different corrdinates than in world objects using regular transform.
    • foo.GetComponent<RectTransform>().localPosition
      makes no sense. localPosition is property of Transform base class. If you don't need the RectTransform part you could have just written
      foo.transform.localPosition
    • When instantiating UI elements (as implied by RectTransform) make sure they are parented directly or indirectly to canvas.
     
    Last edited: Jun 1, 2022
  3. kstrous

    kstrous

    Joined:
    Oct 26, 2021
    Posts:
    7
    Thanks for the help, I'm indeed a beginner so a lot of the time I'm just letting autocomplete do it's thing and hoping it's right lol.

    What I'm trying to do is create a new gameobject from the prefab (so an instance of the prefab?) every time the method is called, I thought this would happen automatically when I instantiate the prefab but if I have to use a separate gameobject and instantiate that as the prefab instead that's fine I think I can do that.

    The problem is that the actual prefab is returning null. I have it as a public variable like you said, and then I drag it in from my prefabs folder into the slot in the editor, but when I try to call that prefab in any way I get null. For example I replaced my code with Debug.log(ingameitemprefab) and Debug.Log(inGameItemPrefab.tag); all I get is null and a nullerror.
     
  4. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    602
    Either I am not understanding what you are trying to say or you misunderstood what I wrote before. Creation of new game object from prefab is the instantiation process. It happens as automatically as I would be expect. I am not sure where you got "use separate gameobject and instantiate that as prefab" . That part of sentence makes no sense to me unless you are using words wrong.


    If you are reference to prefab is null even before you got to the part where you try to instantiate then you are doing something very wrong. Dragging a reference to thing in editor is supposed to be the easy part in whole process, and it's hard for me to explain things any simpler. Unless you have multiple instance of the spawner component and you are dragging the prefab to wrong one, I can't image what else you could do wrong. Maybe you should try looking at some tutorials, that might help you spot the difference in the steps you are doing.
     
  5. kstrous

    kstrous

    Joined:
    Oct 26, 2021
    Posts:
    7
    Update, it seems the problem was I was doing all this from an abstract class, it's weird that it lets you drag in values for an abstract class if they're not going to work but whatever.

    My solution was to create an empty gameobject with a script with a method CreateItem() and I call that from my abstract class.

    I should've mentioned this I guess but I wasn't aware it'd be any different, thanks for the help though.