2 minute read

이 문서는 Udemy의 ‘RPG Core Combat Creator’ 강의를 보고 배운 점을 적은 것입니다.

Saving System

데이터를 저장하고 불러오는 기능

구조

  1. Saving : Saving 관련 컴포넌트들을 가지는 오브젝트 (프리펩)
    1. Saving System : Save / Load 기능이 들어있는 API
    2. Saving Warpper : Saving System을 Input단과 연결시켜주는 중간다리
  2. Other Object : Save / Load 할 데이터가 존재하는 다른 객체들
    1. Saving Entity : Other Object에 붙어서 Saving System과 연결시켜주는 컴포넌트 (uniqueIdentifier를 생성 / 관리하여 이를 기준으로 Saving System과 연결)
    2. Other Component : Other Object 를 구성하는 컴포넌트들, Save / Load 할 실질적인 데이터를 가지고 있다.
      1. ISaveable : Other Component에서 상속받아 사용하는 Save / Load 인터페이스
        이를 통해 Saving Entity와 연결
  3. SerializableVector3 : 기존의 Vector3 클래스는 직렬화가 안되기 때문에 저장을 위해 Vector3 를 자체적으로 직렬화시킨 클래스

즉 Saving System 이 Saving Wrapper (중간 다리)를 거쳐서 각 Other Object들을 관리하게 되는데, 이 때 Saving Entity를 붙여줌으로써 해당 오브젝트가 저장이 필요한지를 가늠할 수 있다. 또한, 오브젝트에 붙어있는 컴포넌트들의 저장은 ISaveable 인터페이스를 사용하므로써 다용성을 확보하여 각 오브젝트마다 필요한 정보들을 저장하거나 불러올 수 있다.

직렬화

객체를 메모리, 데이터 베이스 혹은, 파일로 옮기려면 ‘직렬화’를 거쳐야 한다.
직렬화란 객체를 바이트 스트림으로 바꾸는 것, 즉, 객체에 저장된 데이터를 스트림에 쓰기 위해 연속적(Serial) 데이터로 변환하는 것이다.

직렬화의 주 목적은 객체를 상태 그대로 저장하고, 저장된 데이터에서 다시 그대로 생성하여 사용하는 것이다.

  1. Serialization (직렬화) : 객체의 데이터를 바이트 스트림으로 변환하는 과정
  2. De-Serialization (역직렬화) : 바이트 스트림을 가지고 객체가 저장되었던 바로 그 상태로 변환하는 과정

유니티에서의 직렬화

유니티는 C-Sharp 언어를 사용하므로 그 기준에 따른다.
기본적으로 int, float, string 등의 자료형은 자체 직렬화가 가능하다.
하지만 Vector3 같은 구조체(혹은 클래스)들은 자체 직렬화가 불가능하다. 그래서 아래의 지정자가 필요하다.

System.Serializable

구조체 (혹은 클래스 하략)위에 선언하여, 해당 구조체가 직렬화 가능함을 알리는 지정자이다.
구조체 안의 데이터들은 모두 직렬화 가능한 자료형이여야 한다.
예를 들어 컴포넌트에서 한번에 ‘위치’와 ‘회전값’같이 여러가지 정보를 직렬화 하여 저장하고 싶을 땐, 아래와 같이 구조체를 만든다.

[System.Serializable]
struct MoverSaveData
{
    public SerializableVector3 position;    // 직렬화 가능하게 만든 Vector3
    public SerializableVector3 rotation;    // 직렬화 가능하게 만든 Vector3
};

그리고 저장하고 불러오는 것은 아래와 같이 사용한다.

public object CaptureState()    // object 는 C-Sharp의 모든 구조체의 부모이므로 다형성을 이용할 수 있다.
{
    MoverSaveData data = new MoverSaveData();   // 구조체 생성
    data.position = new SerializableVector3(transform.position);    // 구조체에 데이터 저장
    data.rotation = new SerializableVector3(transform.eulerAngles);

    return data;    // 구조체를 object 형으로 반환
}
public void RestoreState(object state)
{
    GetComponent<NavMeshAgent>().enabled = false;

    MoverSaveData data = (MoverSaveData)state;  // object를 다시 구조체로 형변환
    transform.position = data.position.ToVector();  // 필요한 정보를 불러와서 변수에 저장
    transform.eulerAngles = data.rotation.ToVector();

    GetComponent<NavMeshAgent>().enabled = true;
}

참조

https://medium.com/@lunay0ung/basics-%EC%A7%81%EB%A0%AC%ED%99%94-serialization-%EB%9E%80-feat-java-2f3eb11e9a8