- vừa được xem lúc

Script Serialization trong Unity3D là gì?

0 0 5

Người đăng: Phuong Le

Theo Viblo Asia

Phuongne, Th10 22, 2020


Giới thiệu

Bài viết này giới thiệu về cách mà Unity serialize và hơi lý thuyết, tuy nhiên nó sẽ giúp các bạn tiếp cận về bản chất hơn, hiểu rõ hơn một chút về engine này.

Qua bài này các bạn có thể trả lời một số câu hỏi:

  • Serialization là gì?
  • Làm cách nào Unity có thể lưu trữ các giá trị chỉnh sửa của component trên Inspector?;
  • Những biến như thế nào thì sẽ được unity lưu lại?
  • Unity lưu trữ các biến đã qua chỉnh sửa này ở đâu?

1. Serialization là gì?

Theo Unity Mannual Document, “Serialization là quá trình chuyển trạng thái (dữ liệu) của một object sang một format mà unity có thể lưu trữ và cấu trúc lại”

Mình sẽ lấy ví dụ ở trên Inspector, với các biến public của component khi chỉnh sửa các giá trị của nó:

Chỉnh sửa các biến trên inspector

Vậy các giá trị của 2 biến FullnameFirstname sẽ lưu ở đâu?

Được lưu trữ ở memory, database hoặc file (.unity, .prefab,…), có thể xem đoạn mã ở dưới đây

 m_Name: SchoolManager m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1
--- !u!114 &1104590625
MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1104590624} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: fcee7be6700abe546af43a1352f39c6b, type: 3} m_Name: m_EditorClassIdentifier: principal: fullname: firstName:

Phía trên là một đoạn mã sau khi Unity đã serialize về GameObject có tên là SchoolManager, mình lấy ra từ file MyScene.unity, được định dạng với format kiểu YAML, hay chính xác hơn là UnityYAML.

Tuy nhiên UnityYAML không hỗ trợ đầy đủ chức năng của YAML nên có thể xem UnityYAML như là một phiên bản custom-optimized YAML library.

“các biến nằm trên inspector đều có khả năng Serialize“, tuy nhiên điều ngược lại thì ko đúng vì attribute [HideInInspector] phá vỡ điều này, mình sẽ giải thích ở mục 2.

Để đọc về attribute [HideInInspector], các bạn có thể tham khảo: [SerializeField, Header và một số attributes trong Unity3D (P1)](https://phuongne.com/serializefield-header-attributes-unity3d-p1/(opens in a new tab))

Bởi fullnamefirstname mình đang để trống nên khi serialize thành UnityYAML nó cũng trống, các bạn có thể tự thay đổi, save scene lại và kiểm tra file MyScene.unity (file scene mà các bạn đang thực hành)

“Ngoài file .unity lưu tthông tin đã serialize của scene ra thì còn file nào khác không?”

Các bạn có thể xem file .prefab

“Cái này có cần học không?”

Không, như mình đã nói ở đầu, bài này giúp các bạn rõ hơn về unity.

2. Các quy định về Serialization field

Mình sẽ đưa ví dụ về serialization field trước:

Person.cs – class non-monobehaviour

public class Person
{ public string fullname; [SerializeField] string firstName; private string lastName;
}

School.cs – class MonoBehaviour

public class School : MonoBehaviour
{ public Person principal; public int publicCount = 1; [HideInInspector] public int hidePublicCount = 1; private int privateCount = 2; [SerializeField] private int privateSerializeCount = 2; public static int staticCount = 3; public const int constCount = 4; public readonly int readonlyCount = 5; public Dictionary<string, int> dictionary = new Dictionary<string, int>();
}

School component trên Inspector

Có rất nhiều biến, tuy nhiên Unity chỉ hiện mỗi publicCountprivateSerializeCount, điều này giúp chúng ta có thể rút ra một số luật về serialization, Unity engine chỉ serialize field nếu thỏa mãn:

  1. Nó là public hoặc có gắn thuộc tính [SerializeField]
  2. Không phải là static
  3. Không phải là const
  4. Không phải là readonly
  5. kiểu dữ liệu có thể mà Unity có khả năng serialize (ở ví dụ trên, Dictionary không được hỗ trợ)

“Ủa sao public Person principal không xuất hiện trên Inspector?”

class Person là chúng ta tự tạo, vì vậy cần phải đánh dấu cho Unity biết nó có thể serialize bằng attribute [Serializable]

Và chúng ta cũng có thể đoán được rằng: Unity sẽ chỉ lưu 3 giá trị của Component này dưới dạng UnityYAML, còn các biến khác thì không.

“Sao lại 3, mình thấy chỉ có 2 biến xuất hiện trên inspector mà?”

Như mình đã nói ở phần 1, “…attribute [HideInInspector] phá vỡ điều này”, biến hidePublicCount không xuất hiện trên inspector nhưng cũng được Unity serialize và lưu lại dưới dạng UnityYAML:

MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 980147355} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 4d41c37069812cb4dabc420a408b6178, type: 3} m_Name: m_EditorClassIdentifier: publicCount: 1 hidePublicCount: 1 privateSerializeCount: 2
--- !u!4 &980147357

Đó cũng là lý do khi chúng ta tắt đi mở lại engine Unity, các giá trị này vẫn nằm trên Scene, không thay đổi.

Hoặc khi kéo thả prefab lên hierachy để tạo bản copy của prefab (prefab’s instance), Unity sẽ tạo một object hoàn toàn mới, sau đó mới đẩy các dữ liệu đã serialize của prefab vào instance đó.

3. Serialization ứng dụng trong Instantiate()

Phần này mình sẽ đi vào phân tích ví dụ về việc khi mình instantiate một GameObject B từ GameObject A, những giá trị nào sẽ được copy từ component của gameObject A sang component của GameObject B?

public class School : MonoBehaviour
{ public int publicCount = 1; [HideInInspector] public int hidePublicCount = 1; private int privateCount = 2; [SerializeField] private int privateSerializeCount = 2; public static int staticCount = 3; private void Start() { Debug.Log("----------" + gameObject.name + "------------"); Debug.Log("publicCount: " + publicCount); Debug.Log("hidePublicCount: " + hidePublicCount); Debug.Log("privateCount: " + privateCount); Debug.Log("privateSerializeCount: " + privateSerializeCount); Debug.Log("staticCount: " + staticCount); } private void Update() { if (Input.GetKeyDown(KeyCode.A)) { publicCount *= 10; hidePublicCount *= 10; privateCount *= 10; privateSerializeCount *= 10; staticCount *= 10; } else if (Input.GetKeyDown(KeyCode.B)) { Instantiate(this.gameObject); } }
}
  • Khi mình nhấn A, giá trị của các biến sẽ đồng loạt x10
  • Khi nhấn B, sẽ tạo ra một bản copy của gameObject này

Có 2 trường hợp xảy ra khi nhấn A -> B, GameObject thứ 2 có giá trị các biến sẽ giống hoàn toàn GameObject sinh ra nó HOẶC chỉ có giá trị của các biến serialize mới được copy?

Đáp án chính xác là đáp án 2

LOG của ví dụ trên

Như mình đã nói ở cuối mục 2, chỉ biến có khả năng serialize mới được đổ vào bản copy, bao gồm publicCount, hidePublicCountprivateSerializeCount.

“Ủa sao biến static staticCount không được serialize nhưng nó vẫn thay đổi?”

Static không serialize, staticCount thay đổi bởi vì nó là biến chung của toàn bộ instance, hay là biến của class.

“Vậy các biến không serialize thì nó sẽ nhận giá trị nào?”

Nhận giá trị default trong script, nếu bạn khai báo int i = 10, hoặc Person abc; thì abc == null

Giá trị default của các biến không serializable này là không đổi, nếu bạn cố gắng thay đổi bằng cách sử dụng [ContextMenu] thì sau khi script compile, sau khi đóng mở project, sau khi load lại scene, sau khi nhấn Play trên Editor,…. giá trị này sẽ về lại giá trị default trong code, bởi Unity không lưu giá trị này ở đâu cả.

Như vậy “Chỉ có các biến serializable mới có khả năng lưu lại giá trị đã chỉnh sửa ở trên Unity Editor.”

Claims

Bài viết được đăng vào 2020, chỉ có giá trị tham khảo các bạn nhé 😉

Nguồn tham khảo

Nguồn tham khảo:

Gamasutra – Introduction to Unity Serialization and Game Data

Unity Document – Script Serialization

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tạo setting game trên inspector.

. Chào các bạn,. Hôm nay chúng ta sẽ cùng tạo 1 setting/config cho game trên inspector nhé. Câu trả lời đó là khi chúng ta cần 1 cái gì đó để thao tác trong editor, trực quan nhất, không cần sửa code để cập nhật dữ liệu.... Và hẳn các bạn cũng từng làm việc với những value trên inspector rồi, ví dụ

0 0 17

- vừa được xem lúc

Hướng dẫn đưa nhân vật từ Mixamo vào demo.

. Chào các bạn. Bài này chúng ta chỉ tìm hiểu cách để lấy model, animation về, setting sao cho nó chạy được trong Unity để làm demo là ngon rồi nhé . Bước 1: Đăng nhập. Hãy tạo tài khoản nếu các bạn chưa có.

0 0 21

- vừa được xem lúc

Cơ bản về Rigidbody trong Unity3D

Phuong Le at 31-10-2019 - phuongne. Bài viết từ 2019 nên chỉ có giá trị tham khảo bạn nhé . . Rigidbody là gì.

0 0 13

- vừa được xem lúc

Một số folder đặc biệt trong Unity

Phuong Le 2019 - phuongne. Bài viết từ 2019 nên chỉ có giá trị tham khảo bạn nhé .

0 0 10

- vừa được xem lúc

Coroutine trong Unity là gì? Có liên quan tới Threads hay không?

Phuongne, Th11 17, 2019. Sơ qua một chút về Coroutine và StartCoroutine(.

0 0 8

- vừa được xem lúc

So sánh nhẹ Coroutine và Invoke

Phuongne - 31-10-2019. . Roài, đây sẽ là một bài viết ngắn nên mình đi vào chi tiết luôn, khởi mở đầu giới thiệu dài dòng nhá anh em. Coroutine với Invoke là gì.

0 0 10