标签:
查找了
Script Serialization
http://docs.unity3d.com/Manual/script-Serialization.html
自定义序列化及例子:
http://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.OnBeforeSerialize.html
和Unity 圣典
在这博友 的基础上 再总结下Unity 的序列化
当Unity在运行时候的能在inspector(检视面板)上看到变量(类,结构等)时候,Unity已经发生了序列化;
Unity序列化的关键字是 Serializable 和 SerializeField.
Serializable: 用于 自定义的,非 abstract 的类. 结构体等 , 使这类型也能序列化
SerializeField: 用于 非public 类型(如private), 使非public 类型也能序列化
脚本的字段需要满足什么条件才能被序列化?(必须同时满足)
1. public 类型,或者有 [SerializeField]
2. 不是 static
3. 不是 const
4. 不是 readonly
5. 类型必须是 Unity 可以序列化的类型
Unity 可以序列化哪类型?
1. 自定义的,非 abstract 的类,且有 [Serializable]
2. 有 [Serializable] 的结构体
3. UnityEngine.Object 的子类的引用
4. 原生类型(int,float,double,bool,string, etc)
5. 以上类型的数组
6. 以上类型的 List<T>
[Serializable] class Animal { public string name; } class MyScript : MonoBehaviour { public Animal[] animals; }
例如在序列化一个变量(类.结构等)的时候,如果这个变量里面有Null,Unity将会的实例化一个新对象,然后序列化,然后进入死循环,因为Unity的序列化在非主线程运行,所以出现这种情况会导致程序性能下降
class Test : MonoBehaviour { public Trouble t; } [Serializable] class Trouble { public Trouble t1; public Trouble t2; public Trouble t3; }
OnBeforeSerialize():
这个方法是运行在Unity序列化前, 用来通知你Unity将准备序列化
OnAfterDeserialize():
这个方法是运行在Unity序列化后,用来通知你Unity将已经序列化完
例如我想创建一个序列化树类型 类里面有为Null变量, 违反了第二条限制,直接让Unity运行序列化,将会导致树类型数据很大, 性能下降.
using UnityEngine; using System.Collections.Generic; using System; public class VerySlowBehaviourDoNotDoThis : MonoBehaviour { [Serializable] public class Node { public string interestingValue = "value"; //The field below is what makes the serialization data become huge because //it introduces a ‘class cycle‘. public List<Node> children = new List<Node>(); } //this gets serialized public Node root = new Node(); void OnGUI() { Display (root); } void Display(Node node) { GUILayout.Label ("Value: "); node.interestingValue = GUILayout.TextField(node.interestingValue, GUILayout.Width(200)); GUILayout.BeginHorizontal (); GUILayout.Space (20); GUILayout.BeginVertical (); foreach (var child in node.children) Display (child); if (GUILayout.Button ("Add child")) node.children.Add (new Node ()); GUILayout.EndVertical (); GUILayout.EndHorizontal (); } }
解决的方法使用ISerializationCallbackReceiver接口: 让你生成一个缓存变量来序列化,而不是直接序列化一个树类型
using UnityEngine; using System.Collections.Generic; using System; public class BehaviourWithTree : MonoBehaviour, ISerializationCallbackReceiver { //node class that is used at runtime public class Node { public string interestingValue = "value"; public List<Node> children = new List<Node>(); } //node class that we will use for serialization [Serializable] public struct SerializableNode { public string interestingValue; public int childCount; public int indexOfFirstChild; } //the root of what we use at runtime. not serialized. Node root = new Node(); //the field we give unity to serialize. public List<SerializableNode> serializedNodes; public void OnBeforeSerialize() { //unity is about to read the serializedNodes field‘s contents. lets make sure //we write out the correct data into that field "just in time". serializedNodes.Clear(); AddNodeToSerializedNodes(root); } void AddNodeToSerializedNodes(Node n) { var serializedNode = new SerializableNode () { interestingValue = n.interestingValue, childCount = n.children.Count, indexOfFirstChild = serializedNodes.Count+1 }; serializedNodes.Add (serializedNode); foreach (var child in n.children) AddNodeToSerializedNodes (child); } public void OnAfterDeserialize() { //Unity has just written new data into the serializedNodes field. //let‘s populate our actual runtime data with those new values. if (serializedNodes.Count > 0) root = ReadNodeFromSerializedNodes (0); else root = new Node (); } Node ReadNodeFromSerializedNodes(int index) { var serializedNode = serializedNodes [index]; var children = new List<Node> (); for(int i=0; i!= serializedNode.childCount; i++) children.Add(ReadNodeFromSerializedNodes(serializedNode.indexOfFirstChild + i)); return new Node() { interestingValue = serializedNode.interestingValue, children = children }; } void OnGUI() { Display (root); } void Display(Node node) { GUILayout.Label ("Value: "); node.interestingValue = GUILayout.TextField(node.interestingValue, GUILayout.Width(200)); GUILayout.BeginHorizontal (); GUILayout.Space (20); GUILayout.BeginVertical (); foreach (var child in node.children) Display (child); if (GUILayout.Button ("Add child")) node.children.Add (new Node ()); GUILayout.EndVertical (); GUILayout.EndHorizontal (); } }
要小心使用序列化,因为序列化并不是运行在主线程!
标签:
原文地址:http://www.cnblogs.com/devhyj/p/4342592.html