12/08/2018, 14:23

Script Serialization trong Unity

Serialization là cốt lõi của Unity Editor. Nhiều tính năng của nó được xây dựng trên đỉnh của hệ thống lõi serialization và đáng kể nhất là khi bạn đang sử dụng Unity Editor, nó serialize thành phần MonoBehaviour được hỗ trợ bởi các script của bạn. Các built-in feature sử dụng serialization ...

Serialization là cốt lõi của Unity Editor. Nhiều tính năng của nó được xây dựng trên đỉnh của hệ thống lõi serialization và đáng kể nhất là khi bạn đang sử dụng Unity Editor, nó serialize thành phần MonoBehaviour được hỗ trợ bởi các script của bạn.

  1. Các built-in feature sử dụng serialization

1.1 Inspector window

Built-in feature sử dụng serialization Inspector không giao tiếp với C # API để biết giá trị của một asset mà nó được kiểm tra: Nó hỏi GameObject để tự serialize, và sau đó hiển thị dữ liệu đã được serialize này.

1.2 Prefabs

Bên trong, một Prefab là dòng dữ liệu tuần tự của một (hoặc nhiều) GameObjects và component. Một ví dụ Prefab là một danh sách các thay đổi đó phải được thực hiện trên dữ liệu serialize cho trường hợp này. Khái niệm Prefab chỉ tồn tại trong quá trình chỉnh sửa dự án trong Unity Editor; những sửa đổi lắp ghép được sao lưu vào một dòng serialization bình thường khi Unity biên tập làm một build, và khi GameObjects được khởi tạo trong build, không có tham chiếu đến các GameObjects là Prefabs.

1.3 Instantiation

Khi bạn gọi Instantiate() vào bất cứ thứ gì tồn tại trong một scene, chẳng hạn như một prefab hoặc một GameObject, Unity Editor serialize các GameObject. (Lưu ý rằng tất cả mọi thứ có nguồn gốc từ UnityEngine.Object có thể được serialize.)

Các Editor sau đó tạo ra một GameObject mới và deserializes (có nghĩa là tải) dữ liệu vào GameObject mới. Tiếp theo, các Editor chạy mã tuần tự như nhau trong một biến thể khác nhau để báo cáo mà UnityEngine.Objects khác đang được tham chiếu. Nó kiểm tra tất cả các tham chiếu UnityEngine.Objects để xem nếu họ là một phần của dữ liệu được Instantiated(). Nếu tham chiếu trỏ đến một "external", như một kết cấu, Editor giữ tham chiếu như nó được. Nếu tham chiếu trỏ đến một "internal", như một child GameObject, Editor vá các tham chiếu đến các bản sao tương ứng.

1.4 Saving

Nếu bạn mở một file .unity Scene với một text editor, và đã thiết lập các Unity Editor để buộc serialization text, nó chạy serializer với một phụ trợ YAML.

1.5 Loading

Backward tương thích được xây dựng trên đầu của serialization. In-Editor YAML tải cũng như tải thời gian chạy của Scene, Asset, và AssetBundles đều sử dụng hệ thống serilization.

1.6 Hot reloading của Unity Editor code

Khi bạn thay đổi một script Unity, Unity serialize tất cả các cửa sổ Editor. (Lưu ý rằng họ cũng xuất phát từ UnityEngine.Object!) Unity sau đó tiêu diệt tất cả các cửa sổ, unload code C# cũ, tải code C# mới, tái tạo lại các cửa sổ, và sau đó deserializes các dòng dữ liệu của các cửa sổ trở lại vào cửa sổ mới.

1.7 Resource.GarbageCollectSharedAssets()

Resource.GarbageCollectSharedAssets () là các native Unity garbage collector. Lưu ý rằng nó có một chức năng khác nhau cho C# garbage collector. Nó chạy sau khi bạn tải một scene, để asertain GameObjects từ scene trước đó không còn tham chiếu, và như vậy có thể được unload. Các Unity garbage collector có nguồn gốc chạy serializer trong một biến thể trong đó GameObjects báo cáo tất cả các reference để UnityEngine.Objects bên ngoài. Đây là cách kết cấu được sử dụng bởi, Scene 1, unload tại Scene2.

Các hệ thống serialization được viết bằng C ++. Nó được sử dụng cho tất cả các loại GameObject nội bộ, chẳng hạn như Textures, AnimationClips, và Camera, ... Serialization xảy ra ở cấp UnityEngine.Object. Mỗi UnityEngine.Object luôn được serialize toàn bộ. Chúng có thể chứa reference để UnityEngine.Object và những reference khác được serialize đúng. 2. Serialization và Monobehaviour

MonoBehaviour component, được hỗ trợ bởi các script của bạn cũng sử dụng serlialization. Bởi vì các yêu cầu hiệu suất rất cao mà các serializer có, nó không luôn luôn cư xử chính xác như một developer C# mong chờ từ một serializer. Dưới đây là một số hướng dẫn cách để tận dụng tốt nhất serliaization.

2.1 Làm sao để chắc rằng một field trong script đã serialize

Đảm bảo rằng:

  • là public, hoặc có [SerializeField] attribute
  • không là static
  • không là const
  • không là readonly
  • có fieldtype là 1 trong các type có thể serialize.

2.2 Fieldtype có thể serialize

  • custom lớp non abstract với [Serializable] attribute
  • custom struct với [Serializable] attribute.
  • reference tới GameObject có thể lấy được từ UnityEngine.Object.
  • kiểu data Primitive
  • mảng, list<T> của một fieldtype có thể serialize

2.3 Những trường hợp serialized thực hiện không như mong muốn

2.3.1 Custom một class như một struct

[Serializable]
class Animal
{
   public string name;
}

class MyScript : MonoBehaviour
{
      public Animal[] animals;
}

Nếu bạn có mảng động vật với ba tham chiếu đến một con vật GameObject duy nhất, trong dòng serializtion, bạn tìm thấy 3 GameObjects. Khi nó deserialized, hiện nay có ba GameObjects khác nhau. Nếu bạn cần phải serialize một đồ thị GameObject phức tạp với sự reference, bạn không thể dựa vào serializer Unity có thể làm tất cả tự động cho bạn; bạn phải làm tự một số công việc để nhận được biểu đồ GameObject serialize. Xem ví dụ dưới đây về cách serialize không tự serialize.

Lưu ý rằng điều này chỉ đúng cho các lớp học tùy chỉnh; họ tuần tự "inline" vì dữ liệu của họ trở thành một phần của dữ liệu tuần tự hoàn chỉnh cho các MonoBehaviour được sử dụng. Khi bạn có các lĩnh vực mà có một tham chiếu đến một lớp native UnityEngine.Object, chẳng hạn như một public Camera myCamera, dữ liệu từ camera mà không phải là tuần tự nội tuyến. Thay vào đó là một tham chiếu thực tế với camera UnityEngine.Object đã serialize.

2.3.2 Không hỗ trợ null cho custom class

Hãy xem xét có bao nhiêu phân bổ được thực hiện khi deserializing một MonoBehaviour sử dụng các script sau đây.

class Test : MonoBehaviour
{
    public Trouble t;
}

[Serializable]
class Trouble
{
   public Trouble t1;
   public Trouble t2;
   public Trouble t3;
}

Nó sẽ không phải xa lạ với mong đợi 1 phân bổ: Đó là của GameObject Test. Nó cũng sẽ không lạ gì để mong đợi 2 phân bổ: Một cho GameObject Test và một cho một GameObject Trouble.

Tuy nhiên, câu trả lời chính xác là 729. Các serializer không hỗ trợ null. Nếu nó serializes một GameObject, và một field là null, Unity khởi tạo một GameObject mới của loại đó, và serialize đó. Rõ ràng điều này có thể dẫn đến chu kỳ vô hạn, vì vậy có một giới hạn độ sâu 7 cấp. Vào thời điểm đó Unity ngừng serialize các field mà có các type của các custom class, struct, list, hoặc mảng.

Vì có quá nhiều hệ thống con của Unity xây dựng trên đỉnh của hệ thống tuần tự, dòng serialization này bất ngờ lớn cho các MonoBehaviour Test là nguyên nhân cho tất cả các hệ thống con thực hiện chậm hơn so với cần thiết.

2.3.3 Không support cho tính đa hình

nếu bạn có một mảng public animals [] và bạn đặt trong một thể hiện của một con chó, một con mèo và một con hươu cao cổ, sau khi serialize, bạn có ba trường hợp của động vật.

Một cách để đối phó với hạn chế này là để nhận ra rằng nó chỉ áp dụng cho các custom class, trong đó có serialize inline. Reference để UnityEngine.Objects khác được serialize như actual reference, và cho những thứ này, đa hình không thực sự làm việc. Tạo một class derive SciptableObject, hoặc một class derive MonoBehaviour, và reference đó. Nhược điểm của việc này là bạn cần lưu trữ Monobehaviour hoặc script GameObject ở đâu đó, và bạn không thể serialize nội tuyến hiệu quả.

Lý do cho những hạn chế này là một trong những nền tảng cốt lõi của hệ thống tuần tự là cách bố trí của các luồng dữ liệu cho một GameObject được biết đến trước thời hạn; nó phụ thuộc vào loại field của class, chứ không phải là những gì xảy ra sẽ được lưu trữ bên trong các field.

0