How to pass data between scenes in Unity

后端 未结 5 1368
误落风尘
误落风尘 2020-11-22 08:30

How can I pass score value from one scene to another?

I\'ve tried the following:

Scene one:

void Start () {
    score = 0;
          


        
5条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-11-22 08:57

    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 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;
    
        // 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 data;
    }
    

    Create Instances

    You can create instances of ScriptableObject either via script

    var scriptableObject = ScriptableObject.CreateInstance();
    

    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 someDatas)
        {
            example.someStringValue = someString;
            example.someCustomData = new CustomDataClass
                                     {
                                         example = someInt;
                                         custom = someVector;
                                         data = new Dictionary();
                                     };
            for(var i = 0; i < someDatas.Count; i++)
            {
                example.someCustomData.data.Add(i, someDatas[i]);
            }
        }
    }
    

    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);
        }
    }
    

    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 of needed I often combine the session persistence with some FileIO 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.

提交回复
热议问题