Engine/Unity

[Unity] 유니티 직렬화(Serialization)

예나월드 2024. 3. 17. 01:13
반응형

 

 

 


 

 

직렬화(Serialization): 데이터 구조 또는 게임 오브젝트 상태를 Unity가 보관하고 나중에 다시 복구할 수 있는 포맷으로 변환하는 자동 프로세스입니다.

 

직렬화라는 개념이 상당히 추상적이고 와닿지가 않아서 각종 블로그, 공식 문서 등을 뒤져가면서 찾은 내용을 바탕으로 직렬화에 대해서 쉽게 설명해 보겠습니다.

 

 


 

 

직렬화는 '어떤 데이터를 읽고, 쓰고, 고치기 쉽게 파일 형식을 변환한 것' 이라고 생각하시면 됩니다.

 

유니티에서 사용하는 직렬화를 다루기 때문에, 유니티를 예시로 들어서 설명을 해드리겠습니다.

 

씬에 Cube 오브젝트가 하나 있다고 가정해 봅시다. 그리고 그 Cube 오브젝트를 클릭하면 인스펙터 창에서 해당 Cube에 대한 정보들을 볼 수가 있죠. 기본적으로 붙는 Component들이 있을 것입니다.

 

 

Cube를 생성하면 자동으로 부착되는 Transform, Mesh Renderer, Box Collider ...

 

 

우리는 이 Cube를 이용해서 게임을 만드는 구성요소로 사용을 하게 될 것입니다. 하지만 게임이 하루아침에 뚝딱! 하고 만들어지는 것은 아니죠?

 

유니티 에디터를 껐다가 다시 키더라도 이 Cube 오브젝트는 남아있어야 하고, 각종 Component들도 값이 초기화되지 않아야 합니다. 직접 게임으로 실행할 때도 마찬가지고요.

 

그렇다면 다음에 에디터를 켰을 때, Cube 오브젝트가 이전 상황 그대로를 유지하려면 어떻게 해야 할까요?

 

 

이 Cube의 상태를 파일에 저장하는 것입니다. 그리고 이것이 직렬화입니다.

 

 

어떻게 보면 당연하죠? Cube의 정보들이 어딘가에 기록이 되어있기 때문에 우리는 편하게 에디터를 껐다 키더라도 이전 상태 그대로 이어받아서 사용할 수 있었습니다.

 

하지만 어떤 식으로 저장이 되는지가 전 궁금했습니다. 직접 보기 전까지는 아직 추상적이란 말이죠😥 그래서 어떤 식으로 저장이 되어있는지도 알아보려 합니다.

 

 

 


 

 

방금 생성된 Cube 오브젝트가 있는 Scene을 텍스트 편집기로 열어줍시다. 확장자가 .unity로 끝나기에 텍스트로 열 수 없을 것 같지만 신기하게도 텍스트 파일로 열 수 있습니다!

 

저는 VSCode를 이용해서 열어보겠습니다.

 

 

 

뭔가 알 수 없는 내용이 많이도 적혀있습니다. 사실 Scene 파일은 YAML로 작성된 텍스트 파일이었습니다.

 

YAML이 무엇이냐면 XML, JSON과 같이 사람이 쉽게 읽을 수 있는 데이터 포맷팅입니다.

 

즉, 유니티 에디터는 씬의 정보가 YAML로 기록된 데이터 파일을 읽어 들여서 각종 설정을 불러올 수 있었던 것입니다.

 

해당 파일을 내리다 보면 저희가 방금 생성한 Cube 오브젝트에 대한 정보도 기록이 되어있겠죠?

 

 

 

 

찾았습니다. GameObject이면서, Name이 Cube인걸 보니 저희가 방금 생성한 Cube라는 것을 알 수 있습니다. 

 

첫 째줄에 보면 이상한 문자들과 숫자들이 뒤엉켜 있는 것을 확인할 수 있는데, !u! 이후에 등장하는 숫자는 오브젝트 클래스를 나타내는 숫자입니다. 즉 1번은 GameObject라는 뜻입니다.

 

& 이후에 등장하는 숫자는 해당 오브젝트의 고유한 fileID입니다. 이 ID는 임의로 할당됩니다.

 

 

그리고 다시 사진을 보시면 m_Component 하위에 4개의 컴포넌트가 있는 것을 확인할 수 있습니다. 저 컴포넌트들은 아까 Cube를 처음 생성할 때 기본적으로 부착되었던 Transform, MeshFilter, MeshRenderer, BoxCollider들입니다.

 

하지만 각 컴포넌트에 대한 정보는 없고 fileID만 있는 모습도 볼 수 있습니다. 각 컴포넌트에 대한 정보는 분리되어 작성되어 있고, 그 고유한 ID를 참조한다는 뜻입니다.

 

순서대로 2004785111, 2004785110, 2004785109, 2004785108를 찾아보면 각 컴포넌트들을 찾을 수 있을 것입니다.

 

2004785108에 해당하는 BoxCollider
2004785109에 해당하는 MeshRenderer
2004785110에 해당하는 MeshFilter
2004785111에 해당하는 Transform

 

 

이렇게 컴포넌트들의 정보를 YAML 형태로 저장하여 오브젝트를 불러오고 있었음을 확인할 수 있습니다.

 

YAML이 아닌 바이너리 데이터(이진 형태)로도 저장이 가능합니다.

 

유니티 에디터에서 Edit-Project Settings-Editor로 들어가시면 Asset Serialization이라는 항목이 보일 겁니다. 거기서 Text 형태로 직렬화를 할지, 바이너리 데이터로 직렬화를 할지 설정도 가능합니다.

 

 

 

 

직렬화 모드를 바이너리로 바꾼다면 헥사 에디터를 사용하여 파일을 열어볼 수 있습니다.

 

알아보기는 힘들지만.. 이런 식으로도 직렬화가 가능하다는 것을 알 수 있습니다.

 

 

YAML과 Binary 형식뿐만 아니라, JSON이나 XML과 같은 형태로도 직렬화가 가능합니다.

 

"유니티에서는 YAML로만 직렬화를 한다!" 라고는 생각하시면 안 됩니다. 

 

사용자가 직접 다른 포맷으로도 직렬화가 가능합니다. 다만 씬, 프리팹 등과 같은 정보는 '유니티가 기본적으로 YAML 구조로 직렬화를 수행한다' 정도로 생각해 주시면 되겠습니다. 

 


 

 

직렬화에 대한 개념은 여기까지 알아보도록 하고

 

우리에게 '직렬화' 라는 단어를 접하게 만든 SerializeField와 Serializable도 같이 알아보도록 합시다.

 

 

SerializeField는 보통 Private 필드를 인스펙터 창에 노출시켜서 에디터 상에서 편집을 하고자 할 때 자주 사용되는 속성이죠?

 

하지만 깊게 파고 들어가 보면 Private 필드를 인스펙터 창에 노출을 시키는 것이 목적이 아니라 직렬화가 목적인 것이었습니다. 따지고 보면 인스펙터 창에 필드가 노출이 되는 이유는 직렬화가 되었기 때문에 따라오는 것이라는 얘기죠.

 

저는 그렇게 되는 이유조차도 궁금했습니다..

 

Public 필드와 Private 필드의 차이가 무엇인가? 직렬화가 되어야만 인스펙터 창에 필드가 노출이 되는 이유는 무엇인가?

 

 

정답은.... 그냥 그렇게 설계됐기 때문입니다.

 

유니티 공식문서 / SerializeField

 

 

유니티 공식문서 / 스크립트 직렬화

 

 

결론적으로,

 

  • public 필드만 자동으로 직렬화를 시키고, private 필드를 직렬화하려면 SerializeField로 명시적 직렬화를 해주어야 한다.
  • 인스펙터 창에는 직렬화된 필드만 노출된다.

 

 

클래스 및 구조체를 직렬화할 때 사용되는 Serializable 또한 마찬가지입니다.

 

유니티 공식문서 / 스크립트 직렬화

 

개인이 직접 정의 한 클래스의 경우 Serializable 속성이 붙어야만 클래스를 직렬화 할 수 있기 때문입니다.

 

하지만 클래스는 껍데기일 뿐, 객체의 필드도 직렬화를 해주는 과정을 거쳐야 합니다.

 

 


 

 

아까 생성한 Cube에 스크립트를 부착하고, 해당 스크립트의 Private 필드에 SerializeField를 추가했을 때 직렬화 된 파일을 확인하고 포스팅 마치도록 하겠습니다.

 

public class TestScript : MonoBehaviour
{
    public float a;
    
    private float b;
    
    [SerializeField]
    private float c;
}

 

 

float 변수 중 하나는 public, 하나는 private, 마지막 하나는 private에 SerializeField를 추가하였습니다.

 

이제 스크립트를 부착한 다음 씬 파일을 VSCode로 열어보겠습니다.

 

 

아까는 4개였던 컴포넌트가 스크립트 추가로 인해 5개로 늘어난 모습

 

 

해당 fileID를 따라가 봅시다.

 

 

 

 

MonoBehaviour가 나오고 아래쪽에 방금 추가한 필드들이 보이는 것을 보실 수 있습니다.

 

즉, public 필드는 자동으로 직렬화가 되었고, private 필드는 SerializeField가 추가된 필드만 직렬화가 되었음을 알 수 있습니다.

 

 


 

 

직렬화에 대한 포스팅은 여기서 마치도록 하겠습니다.

저와 같이 추상적인 개념에 이해를 못 하던 분들께 도움이 되기를 바라며.. 😅

 

제가 틀린 내용이 있다면 댓글로 알려주시면 수정하도록 하겠습니다!

 

유니티 공식문서 - SerializeField

유니티 공식문서 - Serializable

유니티 공식문서 - Script serialization

반응형