I am having trouble moving a prefab from scene to scene. This prefab keeps track of the points gained by a player and I want it to be able to track these points over the multiple scenes I have. My only problem is, since the prefab starts in scene one I do not know how to reference it into scene 2. Any help would be awesome!
Generally the pattern used here is called a GameManager: the GameManager is marked as persistent and does not go away until you tell it to by Destroy()-ing it. It would track all your scores and stuff. Look up tutorials on GameManagers. Here’s some example code:
Simple Singleton (UnitySingleton):
Some super-simple Singleton examples to take and modify:
Simple Unity3D Singleton (no predefined data):
Unity3D Singleton with Prefab used for predefined data:
These are pure-code solutions, do not put anything into any scene, just access it via .Instance!
Ok, so I am implementing these things and having a problem starting the Singleton. It says access with SingletonViaPrefab.Instance and I am confused on how to do that.
Whatever your classname is, let’s say AJMRacerGameManager, that’s what:
- the C# file should be called (AJMRacerGameManager.cs - perfect spelling and capitalization)
- the classname should be called
- the way you access it would always be:
AJMRacerGameManager.Instance to call stuff in there.
If you want it to go away (such as after the game is over, or before starting a new game), just destroy it and the next time you access it, it will come back afresh.
So after working on my code for a little bit I have this.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Starter : MonoBehaviour
{
public static Singleton Singleton;
public static Doubleton doubles;
public void Start()
{
Singleton.Instance;
}
}
But I am still getting CS0201 on line 12.
Good lord, NOBODY remembers error codes and I am not about to go type that into google for you.
How to report your problem productively in the Unity3D forums:
That code above has NOTHING to do with the singleton links I posted above. It appears you have actually deleted all of the code that makes the class a singleton!
I am trying to access the singleton. The code that you linked is in another script. I am trying to figure out how to execute it because it does not work on its own. I have the singleton but do not know how to start it.
Here is my Singleton code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// by @kurtdekker - to make a Unity singleton that has some
// prefab-stored, data associated with it, eg a music manager
//
// To use: access with Singleton.Instance
//
// To set up:
// - Copy this file (duplicate it)
// - rename class SingletonViaPrefab to your own classname
// - rename CS file too
// - create the prefab asset associated with this singleton
// NOTE: read docs on Resources.Load() for where it must exist!!
//
// DO NOT DRAG THE PREFAB INTO A SCENE! THIS CODE AUTO-INSTANTIATES IT!
//
// I do not recommend subclassing unless you really know what you’re doing.
public class Singleton : MonoBehaviour
{
// This is really the only blurb of code you need to implement a Unity singleton
private static Singleton _Instance;
public static Singleton Instance
{
get
{
if (!_Instance)
{
// NOTE: read docs to see directory requirements for Resources.Load!
var prefab = Resources.Load(“Prefabs/GameManager”);
// create the prefab in your scene
var inScene = Instantiate(prefab);
// try find the instance inside the prefab
_Instance = inScene.GetComponentInChildren();
// guess there isn’t one, add one
if (!_Instance) _Instance = inScene.AddComponent();
// mark root as DontDestroyOnLoad();
DontDestroyOnLoad(_Instance.transform.root.gameObject);
}
return _Instance;
}
}
// implement your Awake, Start, Update, or other methods here…
void Start()
{
UnityEngine.Debug.Log(“I’m In!”);
}
}
Put when I run my game the Prefab does not appear in the game not do I get my debug message.
Excellent, now I got you. REMOVE the above public static Singleton
variable. That’s the entire point of this is to NOT need that in every script.
In your Starter class, to get it going, you actually can just do this:
void Start()
{
AJMRacerGameManager.Instance.ToString();
}
But… I prefer to have a very explicit method such as StartNewGame();
because that makes sense.
So lets say your Starter now has:
void Start()
{
AJMRacerGameManager.Instance.StartNewGame();
}
In your AJMRacerGameManager class you would have a StartNewGame() method:
public void StartNewGame()
{
myScore = 0;
}
Once that is set up, you can make it as complicated or extensive as you want, adding event listeners or whatever you like to update that score.
If you just want cheap and cheerful to display that score anywhere in your game, just make a little stub script to put on the Text UI object, something like this:
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof( Text))]
public class UpdateScoreText : MonoBehaviour
{
int lastScore;
void DoUpdate()
{
lastScore = AJMRacerGameManager.Instance.myScore;
GetComponent<Text>().text = "Score:" + lastScore;
}
void Start ()
{
DoUpdate();
}
void Update ()
{
if (lastScore != AJMRacerGameManager.Instance.myScore)
{
DoUpdate();
}
}
}
Same could go for any other UI stuff like number of lives, level name, messages to the user (HURRY!) etc.
The key is, you can completely rip-tear-shred and add new scenes, change UI, make a mobile phone version, etc., and your GameManager code never changes for any of that stuff.
Ok, so everything is going pretty good but I have my myScore int located in the singleton. How do I reference the myScore outside of the Singleton script so I can add values to it?
See line 11 in the script I posted above? There you go!
As an aside, I always like to make an AddPoints() method in my GameManager, but there’s no requirement to do so. It just clears up intentions.
public void AddPoints( int points)
{
myScore += points;
}
Then to add points:
AJMRacerGameManager.Instance.AddPoints(100);
I tired to implement the score system like you suggested but when I try to add points I get an Argument Exception saying the object I want to instantiate is null. And for the point update script what do I have to plug in there as when I run it I get null errors.
Point Script:
public void OptionOne()
{
Singleton.Instance.AddPoints(100);
UnityEngine.Debug.Log("You are Weak");
}
I see from your code above you selected the Singleton that loads a prefab. Do you need that? If you do, did you create the appropriate prefab and put it in the folder where the Resources.Load() is accessing it?
If you do NOT need it to load a prefab (and presently I cannot imagine why you would), I recommend using the no-prefab version.
Remember, you have to be able to reason about this stuff on your own. Null references are the single most common error ever.
Some notes on how to fix a NullReferenceException error in Unity3D
- also known as: Unassigned Reference Exception
- also known as: Missing Reference Exception
The basic steps outlined above are:
- Identify what is null
- Identify why it is null
- Fix that.
Expect to see this error a LOT. It’s easily the most common thing to do when working. Learn how to fix it rapidly. It’s easy. See the above link for more tips.
This is the kind of mindset and thinking process you need to bring to this problem:
https://discussions.unity.com/t/814091/4
Step by step, break it down, find the problem.
I can’t believe this. I switch to the no prefab singleton like you suggested and then boom. No more problems. Thank you for all your help!
You’re welcome! Glad it’s working.
I recommend you walk your brain through the actual steps that thing does because a) it is awesomely simple, b) it is awesomely powerful, and c) you will start to think more in the Unity Way™.
This might also help you reason about lifecycles like this:
Here is some timing diagram help: