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 Referencing a script on a prefab that hasnt been instantiated yet

Discussion in 'Scripting' started by warrenbrandt, Apr 18, 2023.

  1. warrenbrandt

    warrenbrandt

    Joined:
    Mar 3, 2018
    Posts:
    413
    Hi guys,

    I have a game manager object that sits in the hierarchy
    how can i reference the script on a prefab that hasnt been instantiated yet so i can get to its varibles?
    i tried dragging it into a public gameobject slot in the inspector but it just causes a reference error.
     
  2. Olipool

    Olipool

    Joined:
    Feb 8, 2015
    Posts:
    316
    You can't use objects outside of the prefab as part/reference of/in a prefab. Because you can't be sure that that object exists in the scene (especially THAT object you dragged in there) when you instantiate the prefab. What if you instantiate it in another scene?
    One solution would be to make your game manager a Unity singleton and then just use it like
    GameManager.Instance.variable1
    Or you can have FindObjectOfType<GameManager>() in the Start() of your prefab and store the found object in the prefab instance.
     
  3. warrenbrandt

    warrenbrandt

    Joined:
    Mar 3, 2018
    Posts:
    413
    Hi olipool

    Thanks for replying

    The game manager is in the hierarchy, and the gameobject called Frog is being instantiated in the scene after some time, i want game manager to be able to reference the script on the frog to establish when a button was pressed.
     
  4. Olipool

    Olipool

    Joined:
    Feb 8, 2015
    Posts:
    316
    Ah thanks, I misunderstood. So how is the frog instantiated? Does the game manager do that? Can you post some code?
     
  5. MartinMa_

    MartinMa_

    Joined:
    Jan 3, 2021
    Posts:
    455
    Code (CSharp):
    1. public class YourGameManager : MonoBehaviour
    2. {
    3.     [SerializeField] private GameObject yourPrefab;
    4.     [SerializeField] private Button yourButton;
    5.     private GameObject yourGameobject;
    6.     void Start()
    7.     {
    8.         yourGameobject = Instantiate(yourPrefab);
    9.         yourButton.onClick.AddListener(AccessComponent);
    10.  
    11.     }
    12.     private void AccessComponent()
    13.     {
    14.         yourGameobject.GetComponent<YourComponent>().WhateverMethodYouHaveOnComponent();
    15.     }
    16. }
    You must set both button and your prefab in editor + your prefab must have script "YourComponent"
     
    Olipool likes this.
  6. warrenbrandt

    warrenbrandt

    Joined:
    Mar 3, 2018
    Posts:
    413
    So im trying to detect when the frog button is clicked...then wait and say "Good you found the frog" , then move onto the next animal....so essentially im trying to get game manager to know when frogTouched is true.

    This is my game manager

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class AnimalManager : MonoBehaviour
    7. {
    8.     //call infobox ic.WriteTextToScreen("Find Freddie the frog.");
    9.     public InfoControl ic;
    10.     private bool animalSelected = false;
    11.     private List<int> availableNumbers = new List<int>();
    12.     private List<int> selectedNumbers = new List<int>();
    13.  
    14.     public GameObject frog;
    15.     private float randomFrogSpawn;
    16.     public GameObject frogSpawner;
    17.     public FrogController fc;
    18.     private bool foundFrog = false;
    19.  
    20.     public GameObject owl;
    21.  
    22.  
    23.     void Start()
    24.     {
    25.        
    26.         // Populate the available numbers list with the numbers 1 to 3
    27.         for (int i = 1; i <= 3; i++)
    28.         {
    29.             availableNumbers.Add(i);
    30.         }
    31.  
    32.         Invoke("StartGame", 3);
    33.  
    34.     }
    35.  
    36.     private void Update()
    37.     {
    38.         fc = GameObject.FindWithTag("Frog").GetComponent<FrogController>();
    39.         print("Animal selected = " + animalSelected);
    40.         RandomAnimalSelector();
    41.     }
    42.  
    43.     void LoadNextAnimal()
    44.     {
    45.  
    46.     }
    47.  
    48.     void StartGame()
    49.     {
    50.         ic.WriteTextToScreen("Welcome to the forest.");
    51.     }
    52.  
    53.     void RandomAnimalSelector()
    54.     {
    55.        
    56.         // If there are still numbers available, select one at random
    57.         if (availableNumbers.Count > 0)
    58.         {
    59.             int randomIndex = Random.Range(0, availableNumbers.Count);
    60.             int selectedNumber = availableNumbers[randomIndex];
    61.             if (!animalSelected)
    62.             {
    63.                 // Add the selected number to the selected numbers list
    64.                 selectedNumbers.Add(selectedNumber);
    65.  
    66.                 // Remove the selected number from the available numbers list
    67.                 availableNumbers.RemoveAt(randomIndex);
    68.  
    69.                 Debug.Log("Selected number: " + selectedNumber);
    70.  
    71.                 switch (selectedNumber)
    72.                 {
    73.                     case 1:
    74.                         Invoke("SpawnFrog", 15);
    75.                         animalSelected = true;
    76.                         break;
    77.                     case 2:
    78.                         Invoke("ShowOwl", 15);
    79.                         animalSelected = true;
    80.                         break;
    81.                 }
    82.             }
    83.         }
    84.         else
    85.         {
    86.             Debug.Log("Game complete...");
    87.         }
    88.     }
    89.  
    90.     public void SpawnFrog()
    91.     {
    92.         animalSelected = true;
    93.         ic.WriteTextToScreen("Find Freddie the frog.");
    94.         randomFrogSpawn = Random.Range(-3, 9);
    95.         frogSpawner.transform.position = new Vector2(randomFrogSpawn, 0.1f);
    96.         GameObject newPlayer = Instantiate(frog, frogSpawner.transform.position, transform.rotation);
    97.     }
    98.  
    99.     public void ShowOwl()
    100.     {
    101.         ic.WriteTextToScreen("Find Ollie the owl.");
    102.         animalSelected = true;
    103.         owl.SetActive(true);
    104.     }
    105. }
    106.  
    And this is my Frog

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class FrogController : MonoBehaviour
    6. {
    7.     public bool frogTouched = false;
    8.     public AudioSource frogSound;
    9.  
    10.     public void PlayFrogSound()
    11.     {
    12.         frogSound.Play();
    13.         frogTouched = true;
    14.     }
    15. }
    16.  
     
  7. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,921
    Unless things have changed, the script on a prefab is found the same way the script on an object is -- use x.GetComponent<scriptName>(), where x is either the prefab or the result of Instantiate. BUT, IMHO there's almost never a reason to look the the prefab's variables. If you want to "save" a setting for object's you instantiate it's better to use your own variables than to try a "change prefab so from now on instantiated objects have that new value".
     
  8. MartinMa_

    MartinMa_

    Joined:
    Jan 3, 2021
    Posts:
    455

    You can do it exactly same how i posted in my answer.I dont't understand why you have 2 lists with numbers and also why you trying find gameobject in update function what is waste of resources.If you want see if animal was touched you cant store list of instantiated GameObjects and check if some variable is true ins some loop for example.
     
  9. warrenbrandt

    warrenbrandt

    Joined:
    Mar 3, 2018
    Posts:
    413
    Hi Owen, if i try reference it that way i just get an error as the frog hasnt been instantiated yet. I only want to read a variable on my frog object.
     
  10. MartinMa_

    MartinMa_

    Joined:
    Jan 3, 2021
    Posts:
    455
    It is because you never store reference for your "frog" and you never access it. If you want read some variable from instantiated gameobject you must store reference. You are not doing that.

    Code (CSharp):
    1. GameObject newPlayer = Instantiate(frog, frogSpawner.transform.position, transform.rotation);
    2.  
    Make your SpawnFrog() to return Gameobject and store this gameobject to some variable and then access this variable and component on it
     
  11. warrenbrandt

    warrenbrandt

    Joined:
    Mar 3, 2018
    Posts:
    413
    Hi

    the two lists are to check that the same number is never selected again.
    wouldnt a reference be better in update to repeat checking for the object...in start its only going to look once.
    sorry, im very bad at this lol
     
  12. MartinMa_

    MartinMa_

    Joined:
    Jan 3, 2021
    Posts:
    455
    You can use Coroutine or
    1. InvokeRepeating ("MySpawnFunction", spawnTime, spawnTime);
    Def. no need update function what update every frame..
     
    warrenbrandt likes this.
  13. warrenbrandt

    warrenbrandt

    Joined:
    Mar 3, 2018
    Posts:
    413
    im really better off doing something like this, than messing with a loop and a switch to select a random game object?

    Code (CSharp):
    1. public GameObject getRandomItem(GameObject[] items)
    2. {
    3.      return items[Random.Range(0, items.Length)];
    4. }
    5. //example of use:
    6. void SomeFunction()
    7. {
    8.      GameObject[] someItems;
    9.      someItems = Resources.LoadAll<GameObject>("Game_Items");
    10.      GameObject randomItem = getRandomItem(someItems);
    11. }
     
  14. MartinMa_

    MartinMa_

    Joined:
    Jan 3, 2021
    Posts:
    455
    You still need to store reference of "randomItem" outside of this function if you want access it from somwhere else, or just return it from you function as you did above.And if you have some prefabs what are same you could consider use of scriptable objects, it save you alot of time.
     
    warrenbrandt likes this.