- Home /
How to create script linked to scene?
Hi, i create a script "finish.cs", it have 2 public values:
-maxScore
-next_level
that are changeable from inspecor. I want to make this script universal for each scene, but when i edit eg. maxScore in scene 1, this value is assigned aslo to maxScore from scene 2. How can i avoid this? here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class finish : MonoBehaviour {
public TextMesh textMesh; //connect score display text
public int maxScore = 3; //max score on level
public string next_level; //next level name
void Start()
{
}
private void OnTriggerEnter(Collider collision)
{
if (collision.gameObject.name == "Sphere")
{
string wynik = textMesh.text; //conversion of score
int Iwynik; //to int and check if
int.TryParse(wynik, out Iwynik); //its equal to max score
if (Iwynik == maxScore)
{
Debug.Log("level change"); //just debug
textMesh.text = "0"; //score reset
SceneManager.LoadScene(next_level); //load next scene
}
}
Debug.Log(collision.gameObject.name); //just debug
}
}
Answer by Mercbaker · Jul 02, 2017 at 01:39 AM
When you hit run:
finish.class is created and maxScore is assigned to 3
When you switch scenes, finish.class is Destroyed
When you load another scene that requres finish.class, it is created again and maxScore is assigned to 3 (once again)
If you want data to persist between scene changes you need to make those classes a "Singleton".
A very convenient way to achieve this is to make a class with the following code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour {
private static T instance;
public static T Instance {
get {
T obj = FindObjectOfType<T>();
if (instance == null) {
instance = obj;
} else if (instance != obj) {
Destroy(obj);
}
obj.transform.SetParent(null);
DontDestroyOnLoad(obj);
return instance;
}
}
}
Now instead of finish.class extending MonoBehavior, make it extend the Singleton.
public class finish : Singleton<finish>{
Your variable will not be destroyed and replaced when you switch scenes. Remember to only make classes a "Singleton" if they are unique.
Good singleton classes are GameManagers, PlayerInventory, SceneManagers, or stuff like Appendixes. All stuff that should be static.
Sorry i see small fail in my code, there shoudn't be "3" just empty value, to choose from inspector. So i made a new script named Singleto, and then in my finish extend it with this script? Sorry for stupid question but im not england. And after doing so i can easily manage those 2 values for every scene independent?
If you implement the above you can switch scenes and keep the original values on the script.
This a time-honored solution, explained very well here. I'll just add a couple comments.
All code that needs to reference the singleton must use the static method Instance. In this case, the
finishclass singleton would be found by callingfinish.Instance. (I recent had code that was callingFindObjectOfTypeto find a singleton object. This almost always worked, but there was a subtle bug when it is called in the first frame of a new scene-- it can find the duplicate object before the singleton code (line 16) has finished destroying it.)The singleton's
Instancemethod callsFindObjectByTypeevery time, and that's a slow function. So if you have a GameObject calling Singleton.Instance inside its Update loop, you should ins$$anonymous$$d do it once and store the result in a local variable.
Thanks for extra comments, in my code finish execute only once per scene - on collision, also changing scenes always take some time, even in main menu you need about 5seconds before choosing first level. So i think its enough time to create new instance and delete old, for now it works really well. But for future can you give me example how i can easy save instance in variable? ( if i need someday use it with update loop script) I hope that i wont use singleton again, dont want to overuse it but if someday i need singelot for self updating script i wont have any idea how to implement it. Its A new thing for me, thanks again for your reply :)
Your singleton getter implementation shouldn't call FindObjectOfType every time. If you do that you wouldn't need any static variable at all. The point of the static variable is to provide a quick access to the "one" instance.
It should be something like this:
private static T instance = null;
public static T Instance {
get {
if (instance == null) {
instance = FindObjectOfType<T>();
if (instance == null)
instance = (new GameObject(typeof(T).Name)).AddComponent<T>();
instance.transform.SetParent(null);
DontDestroyOnLoad(instance);
}
return instance;
}
}
Implementing a check for destroying duplicates inside the getter makes no sense. "FindObjectOfType" simple returns "the first" instance it encounters. So it can return the same instance that is stored inside the static variable but there could still be another instance which you wouldn't catch that way.
A common way is to implement the destroy check in Awake:
protected virtual void Awake()
{
if (this != Instance)
Destroy(gameObject);
}
Answer by ahmad-hadia · Jul 02, 2017 at 01:47 AM
okay first you must to build scenes and you know, then you can declare script in other scenes ,or another solve to create game object in scene 1 and add script to it ,and use (dont destroy on load) .
Your answer