6
\$\begingroup\$

My game requires the changing of scenes. My game also requires the health to stay the same and not get destroyed in the transition of the scene. Which I did with the use of DontDestroyOnload. In the second scene, I want one of the game object's script to use the health bar(which is in the first scene and using DontDestroyOnload). how do I do that?

\$\endgroup\$
0

1 Answer 1

8
\$\begingroup\$

There are a couple of ways you could obtain/retain reference to a game object between scenes. You could use GameObject.Find to find the game object in your new scene, or you could simply use DontDestroyOnLoad() to retain the original reference from the previous scene on a 'controller' script. Note that these methods work for all component types, but I will be using Texture2D as an example.

Using GameObject.Find to find a game object in your scene

There are a couple of useful functions for finding game objects, in Unity. You can ideally use any of them to set up your reference prior to accessing the game object containing your health.

You will find that some are better for finding the specific game object, while others are more useful when trying to grab a reference to a component on the game object.

Keep in mind that GameObject.Find functions will return null if nothing is found. As a matter of good housekeeping, it might be worth double checking that your retrieved reference !- null before continuing to access it.

Finding a game object by name or tag

By searching for an object by name or tag, you are specifically looking using a string identifier. That means that if you ensure your desired object has a unique name or tag, you ensure that you will grab the correct reference.

// You can find a GameObject by name
GameObject.Find("nameOfObject");               // single

// You can find GameObject(s) by tag
GameObject.FindWithTag("objectTag");           // single
GameObject.FindGameObjectByTag("objectTag");   // single
GameObject.FindGameObjectsByTag("objectTag");  // array

In the case where you have multiple objects that match the name or tag, but only call for a single game object, it will not necessarily return any particular instance. On multiple iterations, I had the function return the first instance, before defaulting to the very last instance. If you intend to retrieve a unique object, give it a unique name or tag.

If you intend to access a specific component, you can store the reference to the game object, or simply grab the component reference inline.

// Storing the GameObject reference to retrieve a component
GameObject gameObject = GameObject.Find("nameOfObject");
Texture2D texture = gameObject.GetComponenet<Texture2D>();

// Storing the Component reference, inline
Texture2D texture = GameObject.Find("nameOfObject").GetComponent<Texture2D>();

All of the GameObject.Find functions allow inline component retrieval in this way.

Finding a component by type in your scene

By searching for an object of type, you specifically look for references to the internal components on a game object. You can do this with the <type> variation, or specify a typeof() in the function call. Keep in mind that these functions traditionally return an Object; you will have to cast them to the correct type you wish to retrieve. If you wish to use these functions to find a GameObject, for any reason, you can use the (GameObject) cast.

Once more, when looking for a single component there appears to be no real guarantee that any specific component will be retrieved. If you are looking for an individual reference, I would recommend only using this method if you are ensured there is only one instance of the component in your scene. You can also use the type of a specific script, to directly grab reference to other scripts. This might be the most useful approach for using this method in the described scenario.

// using type specifier
Texture2D texture = GameObject.FindObjectByType<Texture2D>();                     // single
Texture2D[] texture = GameObject.FindObjectsByType<Texture2D>();                  // array

// using typeof and casting
Texture2D texture = (Texture2D)GameObject.FindObjectByType(typeof(Texture2D));    // single
Texture2D[] texture = (Texture2D)GameObject.FindObjectsByType(typeof(Texture2D)); // array

// using typeof and casting to retrieve the GameObject reference
GameObject texture = (GameObject )GameObject.FindObjectByType(typeof(Texture2D)); 
GameObject [] texture = (GameObject )GameObject.FindObjectsByType(typeof(Texture2D)); 

Retaining your reference with a persistent controller script

In some cases, it is a better idea to have a central controller script to manage the references and some of the functionality. In this way, you could also use DontDestroyOnLoad() to ensure that your controller persists, thus retaining your reference from the previous scene.

The first step is to set up a global controller script. I tend to favor the static self-reference approach, as I work in a very controlled environment.

using UnityEngine;
using System.Collections.Generic;

public class ComponentManager : MonoBehaviour 
{
    public static ComponentManager control;      // cheeky self-reference
    public Texture2D texture;                    // our component reference

    void Awake()
    {
        control = this;                          // linking the self-reference
        DontDestroyOnLoad(transform.gameObject); // set to dont destroy
    }
}

In this example, I can access my ComponentManager script from any other script, using the line ComponentManager.control. You have to ensure that you only have one instance running, for it to work correctly, but it can be a simple and helpful workaround. Whether you want to use the GameObject.Find methods to initially load the components in, or use the editor to drag and drop, its completely up to you.

There are other, and far better, ways to approach creating a central 'control script'. Though I am still fairly new to the concept, I am told that Singletons can be helpful in this area. In XNA, I have used services to the same effect, but can not comment on how they relate to or work in Unity. If you are working within a team, discuss other options with them. There will likely be a specific method used to create these static classes, throughout your project, as you will often find need to do so.

\$\endgroup\$
1
  • \$\begingroup\$ the link to singletons on this is bad. \$\endgroup\$
    – DrCord
    Commented Feb 17, 2023 at 21:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .