1

I am creating a simple number guessing game in unity3d.

I want to open a new scene on button click and change the text of a text element present in the loaded scene from the current scene.

I have been able to open new scene on button click but how can i access the text element in other scene so that i can change its text from the current scene. This is what i have so far but it obviously throws NullReferenceException because i can't access the text element in another scene from current scene.

SceneManager.LoadScene("End Scene");
gameResultText.text = "You Won!!";        //<-------this line throws the exception
gameResultText.color = Color.green;

2 Answers2

0

Better solution I came up with:

Make a script that sets a static string variable. This script must be in your Game scene and will hold the result.

public class ResultTextScript : MonoBehaviour
{
    public static string ResultText;

    void EndGame(){
    if (won){ //if won game
            ResultText = "You won!"
       }
       else //if lost game
       {
            ResultText = "You lost, try again another time!"
       }
       //Change scene with SceneManager.LoadScene("");
    }

}

Put this script on your result text in the end scene. This script will retrieve the result and display it.

Using UnityEngine.UI;

public class EndGameDisplayResult{

   Text text; 
   OnEnable(){
   Text.text = ResultTextScript.ResultText
   }
}

This way, it will set the text as soon as the new scene is loaded.





Previous/alternative method:

If you already have the scene open, one option would be to add a script to the "You won!" text which holds a static variable with a reference to itself.

So like this.

public class ResultTextScript : MonoBehaviour
{
    public static ResultTextScript Instance;

    void Awake(){
        if (Instance == null)
            Instance = this;
    }
}

Then you can call the reference to that GameObject from anywhere in the other scripts, including between scenes.

Like this ResultTextScript.Instance

Note though that you cannot call the reference in the Awake method, as that is where the variable is initialized, you can use it after the Awake methods have been called though.

Basically

  1. Add the ResultTextScript to your Text object in the 'End Scene'
  2. Open the 'End Scene' from the 'Game Scene', for example with your SceneManager approach as you already do.
  3. Ensure that the End Scene has loaded, then say in the script you wish to change the text gameObject go = ResultTextScript.Instance.gameObject
Doh09
  • 2,324
  • 1
  • 16
  • 31
  • Changed '!=' to '==', had written the first by mistake. – Doh09 Apr 03 '18 at 19:05
  • `End Scene` is the scene that contains the text element i want to change and currently i am in `Game Scene`. `End Scene` is not already opened. I want to access the text element in `End Scene` from `Game Scene` so i can change its text as i load it. –  Apr 03 '18 at 19:08
  • You already open the Scene with your SceneManager. Please take a look at the better solution I present in answer now. The old answer is below it but check the top answer. – Doh09 Apr 03 '18 at 19:25
0

I do not believe there is a way to modify the context or objects of a scene that is not currently open.

public class GameResults {
   public static string finalText = "";
}

In your function where you are loading the scene, right before you call load scene you can access that text like so:

GameResults.finalText = "You Win!"; or GameResults.finalText = "You Lose!";

load your scene, and on your text object give it a script like this:

using UnityEngine;
using UnityEngine.UI;
public class ResultTextScript : MonoBehaviour
{
    public Text textResults;
    void Start() {
        textResults = getComponent<Text>();
        if(textResults != null) {
            textResults.text = GameResults.finalText;
        }
    }
}

There are other things you can use as well is, storing the game results in PlayerPrefs and loading the string or int you stored in PlayerPrefs preferences at the start of your end scene. This will help you avoid creating an unnecessary class or static variable.

So Like before you can do:

PlayerPrefs.SetString("GameResults", "You Win!"); or PlayerPrefs.SetString("GameResults", "You Lose!");

load your scene, and on your text object give it a script like this:

using UnityEngine;
using UnityEngine.UI;
public class ResultTextScript : MonoBehaviour
{
    public Text textResults;
    void Start() {
        textResults = getComponent<Text>();
        if(textResults != null) {
            textResults.text = PlayerPrefs.GetString("GameResults", "");
        }
    }
}
AresCaelum
  • 1,558
  • 1
  • 13
  • 18
  • The reference I suggested will not be destroyed as it is in the scene he is moving to and not the scene he is leaving. – Doh09 Apr 03 '18 at 19:27
  • Can you guarantee that by the time the next line in that function is called that the scene will have been fully loaded and all objects have had their start called? Also that the instance that your static object is on will have been fully initialized before his text object? You cannot because you do not know how things are laid out in his hierarchy. – AresCaelum Apr 03 '18 at 19:35
  • Yes, because he does not unload the first scene. And even if he did he could still ensure that the text is set before the scene unload is called. The static object will have been initialized when it is set in the variable as it sets itself in its own awake method. The order of his hierarcy is irrelevant. What would be relevant is which method he sets the variable in, in this case the Awake method. Regardless it is now irrelevant as the solution I suggested as a better one only sets a static string which will not be destroyed in any of the cases. – Doh09 Apr 03 '18 at 19:40
  • 1
    @Doh09 per his code he does unload the old scene. he isn't overriding the default secondary parameter which is `LoadSceneMode.Single` which unloads the current scene. https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.LoadScene.html To quote the documentation directly `When using this SceneManager.LoadScene, the loading **does not happen immediately**, it completes in the next frame. ` There is no guarantee that the starts are called before that line in your original post would be ran. – AresCaelum Apr 03 '18 at 19:43
  • 1
    I am afraid that I somehow mistook the loading for an additive scene load and not a regular scene load. In that case you are right that the object approach might not work as I laid it out initially. The new string approach will still work however. – Doh09 Apr 03 '18 at 19:45
  • 1
    @Doh09 yes your new method will work, you are not storing an instance of a monobehaviour it is a static string which wont turn to null in a scene transition. – AresCaelum Apr 03 '18 at 19:46
  • Exactly. A string does not get destroyed. – Doh09 Apr 03 '18 at 19:47