Search Unity

Instantiate object won't work without a parent

Discussion in 'Scripting' started by greglo, Mar 21, 2019.

  1. greglo

    greglo

    Joined:
    Aug 1, 2018
    Posts:
    13
    Hello,

    I am creating a tile-based game. Everything is fine. I'm fine. How are you?

    Unfortunately, the player object is not fine. It refuses to be instantiated or in any way created without setting a parent object. After setting a parent, I can then remove its parent and have it sit normally in the hierarchy.

    I have tried both Instantiate and new GameObject() and many different objects but the result is always the same. After searching high and low, I can't find any comparable case. The new or instantiated object should without setting a parent just exist in the hierarchy alongside the other objects, but it doesn't.

    The setup is this: I am trying to instantiate a gameobject with only a standard transform component and a sprite renderer. The prefab of it is assigned to the MapGenerator script in the inspector using the name player.

    This produces a Player:

    Code (CSharp):
    1.         GameObject playerSprite = Instantiate(player, new Vector3(0, 0, -1), Quaternion.identity, this.transform);
    2.         playerSprite.transform.parent = null;
    3.         playerSprite.name = "Player";
    4.  
    This does nothing:

    Code (CSharp):
    1.       GameObject playerSprite = Instantiate(player, new Vector3(0, 0, -1), Quaternion.identity);
    2.  
    Can anyone tell me why I need to assign a parent else the object does not appear at all?
     
  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
    There are many different instantiate calls, but none require a parent except for UI stuff has to be a child of a canvas, but since you say you are removing the parent, then you are not using UI for this instantiate.

    So, that being said...What is "player". Is it a prefab?
     
  3. greglo

    greglo

    Joined:
    Aug 1, 2018
    Posts:
    13
    Hello Brathnann,

    Yes, "player" is the prefab. It is a simple empty gameobject with a sprite renderer attached with my sprite on it. But the problem occurs also if it is an empty object, a cube, everything.

    Further testing has just shown that creating the player from an invoked function means the player gets instantiated correctly. Is it possible that something happening earlier in the world generation is interfering? I will post the whole script.

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class MapGenerator : MonoBehaviour
    7.     {
    8.  
    9.     [SerializeField]
    10.     private GameObject emptySprite;
    11.     [SerializeField]
    12.     private GameObject player;
    13.  
    14.     [SerializeField]
    15.     private Transform worldSpritesParent;
    16.     [SerializeField]
    17.     private Transform objectSpritesParent;
    18.     [SerializeField]
    19.     private Transform nodeSpritesParent;
    20.  
    21.     public void GenerateLevel1()
    22.         {
    23. // These read the data from the relevant files before generation.
    24.         MapData.CopyLists(MapData.worldIndexBackup1, MapData.worldIndexOriginal1, MapData.worldIndexCopy);
    25.         MapData.CopyLists(MapData.objectIndexBackup1, MapData.objectIndexOriginal1, MapData.objectIndexCopy);
    26.         GenerateWorld();
    27.         GeneratePlayer();
    28.         }
    29.  
    30. // This all works correctly.
    31.     private void GenerateWorld()
    32.         {
    33.         for (int y = 0; y < MapData.mapHeight; y++)
    34.             {
    35.             for (int x = 0; x < MapData.mapWidth; x++)
    36.                 {
    37.                 // Use j for position and y for the index
    38.                 int j = MapData.mapHeight - y;
    39.                 int i = MapData.GetGridIndex(x, y);
    40.                 // Create the sprite
    41.                 GameObject worldSprite = Instantiate(emptySprite, new Vector2(x, j), Quaternion.identity);
    42.                 // Set the parent of the sprite
    43.                 worldSprite.transform.parent = worldSpritesParent;
    44.                 // Add builder component
    45.                 worldSprite.AddComponent<WorldSpriteBuilder>();
    46.                 }
    47.             }
    48.  
    49.         }
    50.  
    51. // This only works with either a parent or an invocation.
    52.     private void GeneratePlayer()
    53.         {
    54.         // Index of the player
    55.         int i, j;
    56.         i = MapData.objectIndexBackup1.IndexOf(999);
    57.         MapData.GetXYIndex(i, out int x, out int y);
    58.         j = MapData.mapHeight - y;
    59.         // Create the sprite
    60.         GameObject playerSprite = Instantiate(player, new Vector3(x, j, -1), Quaternion.identity);
    61.         playerSprite.transform.parent = null;
    62.         playerSprite.name = "Player";
    63.         // Add sprite gameobject to list
    64.         MapBuckets.playerSprite.Add(playerSprite);
    65.         // Get the renderer of the sprite
    66.         SpriteRenderer playerSpriteRenderer = playerSprite.GetComponent<SpriteRenderer>();
    67.         // Add to list
    68.         MapBuckets.playerSpriteRenderer.Add(playerSpriteRenderer);
    69.         }
    70.  
    71.     } // class end
    Of particular interest is the fact that the world sprites have but do not require a parent. They just appear in the hierarchy as expected.
     
  4. WheresMommy

    WheresMommy

    Joined:
    Oct 4, 2012
    Posts:
    890
    Did you try to use SetParent(null). Didnt check it, but maybe this can help. Or just remove the Quaternion.Identity, it is not needed to make Instantiate work.
     
  5. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    It's either getting instantiated and you can't find it, or it's getting instantiated and then immediately destroyed.

    Easy enough to check, give it a name and search for that in the hierarchy:

    Code (csharp):
    1. GameObject playerSprite = Instantiate(player, new Vector3(0, 0, -1), Quaternion.identity);
    2. playerSprite.name = "LOLOLOLOL";
    Search for LOLOLOLOL, see if it's there.
     
    jacobrutter likes this.
  6. greglo

    greglo

    Joined:
    Aug 1, 2018
    Posts:
    13
    Hello,

    Yes, I've tried both of those and no luck.
     
  7. greglo

    greglo

    Joined:
    Aug 1, 2018
    Posts:
    13
    Hello,

    It does not exist in the hierarchy, so I assume it's being created and destroyed. But how?

    Invoking .1 seconds later stops it, so it seems that world generation interferes. But how!
     
    Last edited: Mar 21, 2019
  8. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    Does it have a script on it? In that case, put an OnDestroy method on it. Check if that's getting called.

    In that case, there's for sure one of your scripts calling Destroy on it. You can search your code for places where you call Destroy, see if there's any of that.

    Like perhaps a script that destroys things that fall of the screen or hit a kill trigger or something like that.
     
  9. greglo

    greglo

    Joined:
    Aug 1, 2018
    Posts:
    13
    Unbelievable! It is getting destroyed. It logs a message out from OnDestroy. But my game is practically empty. I'm still in the setup phase. There is only one place where Destroy exists and that is the singleton, which is not being called in this case. In what other circumstances can Unity destroy something? Can I set an object to indestructible? And why does it stop with a parent?
     
  10. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    Unity doesn't automatically destroy objects behind your back. The only instance where that really happens is when you load a new level, in which case objects in the last level gets destroyed.
     
  11. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    ... and to add to Baste's comment: you can override the destruction on Scene Change by Setting 'dontDestroyOnLoad'.

    But I'd go though your existing Level (and especially the Player prefab) with a fine comb indeed, and especially look if any of the script you have attached have an unfilled [RequireComponent]...

    Oh, and make double sure that your Player is not a descendant from the singleton class.

    -ch
     
    Last edited: Mar 21, 2019
  12. greglo

    greglo

    Joined:
    Aug 1, 2018
    Posts:
    13
    Hello everyone,

    What is happening is that I have a play button that uses a delegate to change the scene. It then calls CreatePlayer from the MapGenerator. Somehow, it seems that there is some conflict going on and it results in the player being created a split-second before the scene change has activated. The scene then changes, destroying my player. At least, that's how it seems. Something like that.

    If anyone has any advice on how to handle that, or how to appropriately begin MapGeneration from a button, I would be glad to hear it. If not, thanks for your help and back to cracking this nut. :)
     
  13. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    Perhaps you can delay creating the Player until after Scene loading, by using OnSceneLoaded:

    Code (CSharp):
    1. void Start() {
    2.   SceneManager.sceneLoaded += OnSceneLoaded;
    3. }
    4.  
    5. void OnSceneLoaded() {
    6.   // allocate player
    7. }
     
  14. greglo

    greglo

    Joined:
    Aug 1, 2018
    Posts:
    13
    That's a good point.

    It seems to work with a parent because it is somehow inheriting the Don'tDestroyOnLoad. So that solves that mystery
     
    Last edited: Mar 21, 2019