Trying to change music between scenes - c#

I'm trying to store the current music that is playing in the current scene that I'm on and then in the next scene change it for another one.
Here are my scripts.
AudioManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AudioManager : MonoBehaviour {
public static AudioManager Instance;
private MusicList musicList;
[SerializeField] private AudioSource _effectsSource, currentMusic;
private void Awake() {
if (Instance == null) {
Instance = this;
DontDestroyOnLoad(this);
}
else Destroy(this);
Instance = this;
musicList = GetComponentInChildren<MusicList>();
}
public void PlayMusic(MusicId id) {
AudioSource musicToPlay = musicList.GetMusicSource(id);
musicToPlay.Play();
currentMusic = musicToPlay;
}
public void ChangeMusic(MusicId newMusicId) {
currentMusic.Stop();
AudioSource musicToPlay = musicList.GetMusicSource(newMusicId);
musicToPlay.Play();
currentMusic = musicToPlay;
}
public void PlaySound(AudioClip clip) {
_effectsSource.PlayOneShot(clip, 0.1f);
}
}
MusicList is a children of the AudioManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MusicList : MonoBehaviour
{
public Music[] musicList;
private void Awake()
{
foreach (Music music in musicList) {
music.source = gameObject.AddComponent<AudioSource>();
music.source.clip = music.clip;
music.source.volume = music.volume;
music.source.loop = true;
}
}
public AudioSource GetMusicSource(MusicId id) {
foreach (Music music in musicList) {
if (music.id == id) return music.source;
}
return null;
}
}
Music
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Music
{
public MusicId id;
public AudioClip clip;
[HideInInspector]
public AudioSource source;
public float volume;
}
public enum MusicId {
Menu,
Gameplay
}
When I debug in the first scene the current track playing is stored, but when I change the scene and try to access the currentMusic value it's null.
Thank you for the help!

You have at least two approaches here. One of them is using proprietary scene data (not a technical term), meaning you use whatever info the current scene has, while the other method is using data persistence (this is a technical term) to "save" data in (normally) transient objects after scene changes. There is a third way to persist data, but it's not recommended for your use-case.
There are use-cases for all of them, each having different aims. Let's attack them:
scene info
This is straight forward: you have a menu, a tutorial, 2 levels, a boss fight level then the "end game + credits". This would mean 6 different songs (assuming each scene, including the end-credits has a different theme). Once you switch from menu to level and from level to level and then to "the end", a new song pops-up on the audio manager.
The simplest approach here is to have a GameObject in each scene (preferably with the same name and same components, only the song being different). Let's call it "SceneInfo". On this GO you can attach any info necessary to your level, like some description of the level, objectives, difficulty or song. You can use the Find() function to locate this GO then just access the component you need (like a component that saved the Music, then just pop-it on the AudioSource and Play() it).
Minor note: the scene GO must NOT be set as DontDestroyOnLoad(). Because you must not "carry" it in a different scene since each scene has its own stuff. And, of course, this should be different from your AudioManager GO.
This is prolly what you want for your approach.
data persistence
This is normally used to "carry" player-related stuff like the player icon, player name, health, inventory etc. from an earlier scene to this one. You can "carry" the music too, I guess, assuming it's a custom playlist OR if you want to continue the song. Otherwise, I don't recommend this for music if the songs are always different between levels.
This is basically what you did with your AudioManager.
storage (not recommended for what you need)
There would be a third option related to storage, by using PlayerPrefs, but I think this is overkill just for a song. But feel free to use this if you find it easier. As I said, it all depends on your use-case.
This option refers mostly to game preferences like volume, graphics settings etc. It's basically the "memory" of game settings.
Minor caveats:
I would set currentMusic; as public.
Your Awake() function has a weird flow. else Destroy(this); is missing a return. It's not wise to set the Instance to this since you're destroying the object.
Try this instead:
private void Awake()
{
if (Instance == null)
{
DontDestroyOnLoad(this);
Instance = this;
}
else if (Instance != this)
{
Destroy(this);
return;
}
if (musicList == null)
musicList = GetComponentInChildren<MusicList>();
}
You said: MusicList is a children of the AudioManager. I think you mean component instead of children, if the gameObject it's attached to is called "AudioManager", right? Else it doesn't quite make sense. A child class is something else.
Then the code in PlayMusic() is identical to ChangeMusic() (apart from stopping the previous song to update it). That means if you want to change something in the code for PlayMusic() or ChangeMusic(), you'll always have to do it twice (in each function). This is better:
public void PlayMusic(MusicId id) {
AudioSource musicToPlay = musicList.GetMusicSource(id);
musicToPlay.Play();
currentMusic = musicToPlay;
}
public void ChangeMusic(MusicId newMusicId) {
currentMusic.Stop();
PlayMusic(newMusicId);
}
... which can be simplified even more to this:
public void PlayMusic(MusicId id) {
currentMusic = musicList.GetMusicSource(id);
currentMusic.Play();
}
public void ChangeMusic(MusicId newMusicId) {
currentMusic.Stop();
PlayMusic(newMusicId);
}
And now there is no temp variable. It complicated the code for no reason.
(of course, assuming the id is always guaranteed to be in the list, which, of course, it should be). This way you only have one place to change your code or fix potential bugs.
While you can "force" serialization of C# objects, it's better to use Unity objects (anything from UnityEngine.object, but mostly rely on ScriptableObjects, Components and Prefabs).
The music init workflow is also weird. Instead of initializing the AudioSource on each music wrapper, you do it in a loop in the list. It's a bit "backwards", but not necessarily a bad thing. I just wouldn't do it.

Related

How can I access a scene from another scenes script

I have a homework assigned and I need the make a sound and music volume thing and I want it to be used in other scripts too.
What I mean is :
enter image description here
So when I drag the slider value to 0.2 for example I want the audio source on the other scene to have volume 0.2, but I have no idea how thats made.
Thanks.
(I only have a plan but no code)
Also does anyone know why does it take forever to load when you save a script and go to unity:
enter image description here
A great way to do this is to use static variables that are actually defined for the class And can hold variables between scenes.
public class AudioManager
{
public static float MusicVolume = 1f;
public static float SoundVolume = .5f;
public void SetVolume(float value) => MusicVolume = value;
}
To call them, you just need to write the full name of the class before the variable name.
public class Player : MonoBehaviour
{
public AudioClip AudioClip;
public void Shot()
{
AudioSource.PlayClipAtPoint(AudioClip, transform.position, AudioManager.SoundVolume);
}
}
Remember that these are class variables will set in all instances of the same class. Also if you want your variables to be loaded after re-running the game. I suggest using PlayerPrefs for saving them.
To do this you would write a singleton script AudioManager that is set to DontDestroyOnLoad
It's just a script holding your AudioSources and that doesn't get destroy when you switch scenes.
Something like this
public class AudioManager : MonoBehaviour
{
private static AudioManager instance;
[Header("AudioSources")]
[SerializeField] private AudioSource musicSource;
[SerializeField] private AudioSource soundSource;
private void Awake()
{
// If you have AudioManager in every scene, you want to only keep the main one (the first one)
if (instance != null && instance != this)
{
Destroy(gameObject);
}
else
{
instance = this;
DontDestroyOnLoad(this); // This line will tell Unity to keep this gameobject when switching scenes
}
}
}
Then you can alter your audio sources as you wish, they won't get destroy after switching scene.
Okay Its nice that I have a lot of things to do but okay the script that you guys sent me, so if I put it on the audio Gameobject and I still don't get how I can change parameters from 1 scene to other (I'm a beginner and I'm 13 years old so I might not get what audio ATM's are but yes.)
For short I need this:
Scene1.findgameobject.name = blah blah = audiogameobject in menu

Transfer of float of Input Field to a new Scene and new Script in Unity and C#

I have a car game, you define in one scene all settings, like the speed, after that you can press play, the new scene shows up.
The code of the first Scene is this, it is attached to an empty GameObject:
using UnityEngine;
using UnityEngine.UI;
public class Data : MonoBehaviour {
static public float speed=10f;
public InputField speedField;
void Update()
{
speed = float.Parse(speedField.text);
Debug.Log(speed);
}
}
In the next scene I have to work with speed in a script called Driving, which is attached to the cars. And I have to destroy the Data-Script, because in the next scene I don't have an Input-Field. How can I access to speed?
I tried a couple of hours and I'm not able to find a solution for this easy question. Thanks.
There are many ways you can solve this problem what I will suggest is to use the static script for holding data only, but you cant assign it to game object. It is a simple approach as you don't need to use a singleton.
public static class Data{
private static int speed
public static int speed{
get
{
return speed;
}
set
{
speed = value;
}
}
If you want to assign your script to game object then use DontDestroyOnLoad(gameObject); Or use playerprefs to save data.

how to make a c# script run at scene start in unity

I am doing a school project. I need to check the destroyed objects in my scene as soon as the scene starts. problem is I don't know how to make it load or where to attach the c# script.
public static class DestroyedObject {
static List<GameObject> objs = new List<GameObject>();
public static void Add(GameObject obj)
{
if(!objs.Contains(obj))
objs.Add(obj);
}
}
If you want it to run when you start the scene you need to attach it to a GameObject. Create empty and attach it as a component.
The code that you want to run on start should be in the:
void Awake
{
//Your code here
}
or
void Start
{
//Your code here
}
functions.
Start is called as soon as the class is instantiated and Awake is called when the scene is started. Depends where you want it in the call stack, but in your case i think it will do essentially the same thing.
I think what you're looking for is a way to "save" what objects have been deleted : you simply have to make your class inherit from MonoBehaviour and call DontDestroyOnLoad() so your object containing the script will exist between the scenes.
public static class DestroyedObject : MonoBehaviour
{
public static DestroyedObject Instance;
private static List<GameObject> objs = new List<GameObject>();
private void Awake()
{
if (!Instance)
{
Instance = this;
}
else
{
DestroyImmediate(gameObject);
}
DontDestroyOnLoad(gameObject);
}
public static void Add(GameObject obj)
{
if(!objs.Contains(obj))
objs.Add(obj);
}
public static List<GameObject> GetDestroyedObjects()
{
return objs;
}
}
Then you simply access your script using DestroyedObject.Instance.Add() or DestroyedObject.Instance.GetDestroyedObjects() (some people don't like this kind of design pattern but it has proven to be very effective when using Unity).
Also as #Sergey asked, why creating objects (on scene loading) in order to delete them afterward : you could do the revers operation (only instantiate the needed ones).
Hope this helps,
Can you describe what you are trying to achieve in total? Because it looks like your way is not the best way to do it ;).
If all you want to know is how to execute a script at scene start: create a script that inherits from MonoBehaviour (no need for static class), attach it to a gameobject in your scene, and thats it!
If you want to execute code as soon as the scene starts (and the gameobject is loaded), put your code in Awake() or Start(). You can read about the execution order of those functions here: https://docs.unity3d.com/Manual/ExecutionOrder.html
Making a script static means it will be active in all scenes and even before any scene is loaded.
Additionally, i would not recommend the use of static classes unless you really need them.

Unity3D beginner RestartButton. Sharing information between scenes?

I want a restart menu that works for all my levels, as I load level 1 there is this script setting an integer to 1 on an empty game object.
using UnityEngine;
using System.Collections;
public class SetRestart : MonoBehaviour {
public int Setrestart = 1;
void awake ()
{
DontDestroyOnLoad (this);
}
}
When you fail the level you get to the next scene called: LostMenu. You have the option to restart that level you were playing or quit. So here I made a button to restart and attached this script to it:
using UnityEngine;
using System.Collections;
public class RestartButton : MonoBehaviour
{
public int Setrestart;
void Start()
{
if (Setrestart == 1) {
Application.LoadLevel("Main");
}
}
}
(Plan is to make 50 levels and also 50 if statements, this is just the first one for the first level called "Main", every level will have its own number).
The problem is that nothing happens when I click on the button (Screenshot: http://prntscr.com/9tf4dd) and that when I load the LostMenu screen nothing happens to the int and it stays at 0 in the inspector while in the level scene called: "Main" I said to it to give it 'int = 1.' The number 1 stays in the "Main" scene and doesn't go to the menu scene.
Level 1 is scene: "Main".
The menu to restart when you lose is scene: "LostMenu".
Am I clear? Sorry for my bad English and thank you in advance.
I use a static 'Globals' class to persist data between scenes in Unity.
You could use something like this to store the name of the last level that you played.
public static class Globals
{
public static string LastLevel {get; set;}
}
Then you could just write to this string at the start of your level and read it in your restart button handler.
In order for RestartButton to know about the Setrestart value stored in SetRestart you need to have a reference to the GO with the SetRestart component. Right now RestartButton is checking its own Setrestart value, which defaults to 0. This is why it doesn't work.
Instead you need this:
public class RestartButton : MonoBehaviour
{
GameObject persistentObject;
void Start()
{
persistentObject = GameObject.Find("NameOfGameObject");
int shouldReset = (persistentObject.GetComponent<SetRestart>() as SetRestart).Setrestart;
if (shouldReset == 1) {
Application.LoadLevel("Main");
}
}
}
GameObject.Find isn't great, performance wise, but for a once-off lookup, it's fine. There are also other ways of getting the reference, but in the case of objects that persist across scene changes, this is the only way (note that I'm saving the GameObject reference to a field, while not neccessary here it is good practice so you aren't GO.Find()ing all the time).

How to pass data (and references) between scenes in Unity

How can I pass score value from one scene to another?
I've tried the following:
Scene one:
void Start () {
score = 0;
updateScoreView ();
StartCoroutine (DelayLoadlevel(20));
}
public void updateScoreView(){
score_text.text = "The Score: "+ score;
}
public void AddNewScore(int NewscoreValue){
score = score + NewscoreValue;
updateScoreView ();
}
IEnumerator DelayLoadlevel(float seconds){
yield return new WaitForSeconds(10);
secondsLeft = seconds;
loadingStart = true;
do {
yield return new WaitForSeconds(1);
} while(--secondsLeft >0);
// here I should store my last score before move to level two
PlayerPrefs.SetInt ("player_score", score);
Application.LoadLevel (2);
}
Scene two:
public Text score_text;
private int old_score;
// Use this for initialization
void Start () {
old_score = PlayerPrefs.GetInt ("player_score");
score_text.text = "new score" + old_score.ToString ();
}
but nothing displayed on screen, and there's no error.
Is this the correct way to pass data ?
I am using Unity 5 free edition, develop game for Gear VR (meaning the game will run in android devices).
Any suggestion?
There are many ways to do this but the solution to this depends on the type of data you want to pass between scenes. Components/Scripts and GameObjects are destroyed when new scene is loaded and even when marked as static.
In this answer you can find
Use the static keyword
Use DontDestroyOnLoad
Store the data local
3a PlayerPrefs
3b serialize to XML/JSON/Binary and use FileIO
1. Use the static keyword.
Use this method if the variable to pass to the next scene is not a component, does not inherit from MonoBehaviour and is not a GameObject then make the variable to be static.
Built-in primitive data types such as int, bool, string, float, double. All those variables can be made a static variable.
Example of built-in primitive data types that can be marked as static:
static int counter = 0;
static bool enableAudio = 0;
static float timer = 100;
These should work without problems.
Example of Objects that can be marked as static:
public class MyTestScriptNoMonoBehaviour
{
}
then
static MyTestScriptNoMonoBehaviour testScriptNoMono;
void Start()
{
testScriptNoMono = new MyTestScriptNoMonoBehaviour();
}
Notice that the class does not inherit from MonoBehaviour. This should work.
Example of Objects that cannot be marked as static:
Anything that inherits from Object, Component or GameObject will not work.
1A.Anything that inherits from MonoBehaviour
public class MyTestScript : MonoBehaviour
{
}
then
static MyTestScript testScript;
void Start()
{
testScript = gameObject.AddComponent<MyTestScript>();
}
This will not work because it inherits from MonoBehaviour.
1B.All GameObject:
static GameObject obj;
void Start()
{
obj = new GameObject("My Object");
}
This will not work either because it is a GameObject and GameObject inherit from an Object.
Unity will always destroy its Object even if they are declared with the static keyword.
See #2 for a workaround.
2.Use the DontDestroyOnLoad function.
You only need to use this if the data to keep or pass to the next scene inherits from Object, Component or is a GameObject. This solves the problem described in 1A and 1B.
You can use it to make this GameObject not to destroy when scene unloads:
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
You can even use it with the static keyword solve problem from 1A and 1B:
public class MyTestScript : MonoBehaviour
{
}
then
static MyTestScript testScript;
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
void Start()
{
testScript = gameObject.AddComponent<MyTestScript>();
}
The testScript variable will now be preserved when new scene loads.
3.Save to local storage then load during next scene.
This method should be used when this is a game data that must be preserved when the game is closed and reopened. Example of this is the player high-score, the game settings such as music volume, objects locations, joystick profile data and so on.
Thare are two ways to save this:
3A.Use the PlayerPrefs API.
Use if you have just few variables to save. Let's say player score:
int playerScore = 80;
And we want to save playerScore:
Save the score in the OnDisable function
void OnDisable()
{
PlayerPrefs.SetInt("score", playerScore);
}
Load it in the OnEnable function
void OnEnable()
{
playerScore = PlayerPrefs.GetInt("score");
}
3B.Serialize the data to json, xml or binaray form then save using one of the C# file API such as File.WriteAllBytes and File.ReadAllBytes to save and load files.
Use this method if there are many variables to save.
General, you need to create a class that does not inherit from MonoBehaviour. This class you should use to hold your game data so that in can be easily serialized or de-serialized.
Example of data to save:
[Serializable]
public class PlayerInfo
{
public List<int> ID = new List<int>();
public List<int> Amounts = new List<int>();
public int life = 0;
public float highScore = 0;
}
Grab the DataSaver class which is a wrapper over File.WriteAllBytes and File.ReadAllBytes that makes saving data easier from this post.
Create new instance:
PlayerInfo saveData = new PlayerInfo();
saveData.life = 99;
saveData.highScore = 40;
Save data from PlayerInfo to a file named "players":
DataSaver.saveData(saveData, "players");
Load data from a file named "players":
PlayerInfo loadedData = DataSaver.loadData<PlayerInfo>("players");
There is another way:
ScriptableObject
ScriptableObjects are basically data containers but may also implement own logic. They "live" only in the Assets like prefabs. They can not be used to store data permanently, but they store the data during one session so they can be used to share data and references between Scenes ... and - something I also often needed - between Scenes and an AnimatorController!
Script
First you need a script similar to MonoBehaviours. A simple example of a ScriptableObject might look like
// fileName is the default name when creating a new Instance
// menuName is where to find it in the context menu of Create
[CreateAssetMenu(fileName = "Data", menuName = "Examples/ExamoleScriptableObject")]
public class ExampleScriptableObject : ScriptableObject
{
public string someStringValue = "";
public CustomDataClass someCustomData = null;
public Transform someTransformReference = null;
// Could also implement some methods to set/read data,
// do stuff with the data like parsing between types, fileIO etc
// Especially ScriptableObjects also implement OnEnable and Awake
// so you could still fill them with permanent data via FileIO at the beginning of your app and store the data via FileIO in OnDestroy !!
}
// If you want the data to be stored permanently in the editor
// and e.g. set it via the Inspector
// your types need to be Serializable!
//
// I intentionally used a non-serializable class here to show that also
// non Serializable types can be passed between scenes
public class CustomDataClass
{
public int example;
public Vector3 custom;
public Dictionary<int, byte[]> data;
}
Create Instances
You can create instances of ScriptableObject either via script
var scriptableObject = ScriptableObject.CreateInstance<ExampleScriptableObject>();
or to make things easier use the [CreateAssetMenu] as shown in the example above.
As this created ScriptabeObject instance lives in the Assets it is not bound to a scene and can therefore be referenced everywhere!
This when you want to share the data between two Scenes or also e.g. the Scene and an AnimatorController all you need to do is reference this ScriptableObject instance in both.
Fill Data
I often use e.g. one component to fill the data like
public class ExampleWriter : MonoBehaviour
{
// Here you drag in the ScriptableObject instance via the Inspector in Unity
[SerializeField] private ExampleScriptableObject example;
public void StoreData(string someString, int someInt, Vector3 someVector, List<byte[]> someDatas)
{
example.someStringValue = someString;
example.someCustomData = new CustomDataClass
{
example = someInt;
custom = someVector;
data = new Dictionary<int, byte[]>();
};
for(var i = 0; i < someDatas.Count; i++)
{
example.someCustomData.data.Add(i, someDatas[i]);
}
example.someTransformReference = transform;
}
}
Consume Data
So after you have written and stored your required data into this ExampleScriptableObject instance every other class in any Scene or AnimatorController or also other ScriptableObjects can read this data on just the same way:
public class ExmpleConsumer : MonoBehaviour
{
// Here you drag in the same ScriptableObject instance via the Inspector in Unity
[SerializeField] private ExampleScriptableObject example;
public void ExampleLog()
{
Debug.Log($"string: {example.someString}", this);
Debug.Log($"int: {example.someCustomData.example}", this);
Debug.Log($"vector: {example.someCustomData.custom}", this);
Debug.Log($"data: There are {example.someCustomData.data.Count} entries in data.", this);
Debug.Log($"The data writer {example.someTransformReference.name} is at position {example.someTransformReference.position}", this);
}
}
Persistence
As said the changes in a ScriptableObject itself are only in the Unity Editor really persistent.
In a build they are only persistent during the same session.
Therefore if needed I often combine the session persistence with some FileIO (as described in this answer's section 3b) for loading and deserializing the values once at session begin (or whenever needed) from the hard drive and serialize and store them to a file once on session end (OnApplicationQuit) or whenever needed.
(This won't work with references of course.)
Besides playerPrefs another dirty way is to preserve an object during level loading by calling DontDestroyOnLoad on it.
DontDestroyOnLoad (transform.gameObject);
Any script attached to the game object will survive and so will the variables in the script.
The DontDestroyOnLoad function is generally used to preserve an entire GameObject, including the components attached to it, and any child objects it has in the hierarchy.
You could create an empty GameObject, and place only the script containing the variables you want preserved on it.
I use a functional approach I call Stateless Scenes.
using UnityEngine;
public class MySceneBehaviour: MonoBehaviour {
private static MySceneParams loadSceneRegister = null;
public MySceneParams sceneParams;
public static void loadMyScene(MySceneParams sceneParams, System.Action<MySceneOutcome> callback) {
MySceneBehaviour.loadSceneRegister = sceneParams;
sceneParams.callback = callback;
UnityEngine.SceneManagement.SceneManager.LoadScene("MyScene");
}
public void Awake() {
if (loadSceneRegister != null) sceneParams = loadSceneRegister;
loadSceneRegister = null; // the register has served its purpose, clear the state
}
public void endScene (MySceneOutcome outcome) {
if (sceneParams.callback != null) sceneParams.callback(outcome);
sceneParams.callback = null; // Protect against double calling;
}
}
[System.Serializable]
public class MySceneParams {
public System.Action<MySceneOutcome> callback;
// + inputs of the scene
}
public class MySceneOutcome {
// + outputs of the scene
}
You can keep global state in the caller's scope, so scene inputs and outputs states can be minimized (makes testing easy). To use it you can use anonymous functions:-
MyBigGameServices services ...
MyBigGameState bigState ...
Splash.loadScene(bigState.player.name, () => {
FirstLevel.loadScene(bigState.player, (firstLevelResult) => {
// do something else
services.savePlayer(firstLevelResult);
})
)}
More info at https://corepox.net/devlog/unity-pattern:-stateless-scenes
There are various way, but assuming that you have to pass just some basic data, you can create a singelton instance of a GameController and use that class to store the data.
and, of course DontDestroyOnLoad is mandatory!
public class GameControl : MonoBehaviour
{
//Static reference
public static GameControl control;
//Data to persist
public float health;
public float experience;
void Awake()
{
//Let the gameobject persist over the scenes
DontDestroyOnLoad(gameObject);
//Check if the control instance is null
if (control == null)
{
//This instance becomes the single instance available
control = this;
}
//Otherwise check if the control instance is not this one
else if (control != this)
{
//In case there is a different instance destroy this one.
Destroy(gameObject);
}
}
Here is the full tutorial with some other example.
you have several options.
The first one I see is to use static variables, which you will not lose their information or value passing from scenes to scenes (since they are not bound to the object). [you lose the information when closing the game, but not when passing between scenes]
the second option is that the player or the object of which you do not want to lose the information, you pass it through the DontDestroyOnLoad function
Here I give you the documentation and the sample code. [You lose the information when you close the game, but not when you go between scenes]
https://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html
Third is to use the playerPrefab [https://docs.unity3d.com/ScriptReference/PlayerPrefs.html]
that allow you to save information and retrieve it at any time without hanging it even after closing the game [you must be very careful with the latter if you plan to use it to save data even after closing the game since you can lose the data if you close the game suddenly , since player prefab creates a file and retrieves the information from there, but it saves the file at the end or closes the app correctly]

Categories

Resources