영구 데이터: 게임 상태 및 설정을 저장하는 방법

데이터 절약은 모든 게임에서 매우 중요합니다. 최고 점수, 환경 설정 또는 게임 상태를 저장해야 하는 경우, 유니티는 플레이어 프리프부터 데이터 직렬화, 암호화, 파일에 쓰기 등 다양한 방법을 제공합니다.
2021년 6월 23일에 업데이트되었습니다: 유나이트 나우 2020의 일환으로 유니티의 데이터 지속성에 대한 팁을 제공하는 세션을 준비했습니다. 여기서는 Unity 프로젝트에서 데이터를 저장하고 로드하는 일반적인 방법 몇 가지를 다루지만, 이 목록이 전체 목록은 아닙니다. 즉, 데이터를 직렬화하는 방법은 필요 이상으로 많으며, 각 접근 방식은 특정 문제를 해결하고 고유한 장단점을 가지고 있습니다. 이 블로그 게시물에서는 Unite Now 세션에서 설명한 것과 동일한 일반적인 방법을 다룹니다.
PlayerPref는 게임 상태를 저장하기 위해 만들어지지 않았습니다. 하지만 유용한 기능이므로 이에 대해 설명하겠습니다. 플레이어 환경설정을 사용하여 세션 간에 품질 설정, 오디오 볼륨 또는 기타 비필수 데이터와 같은 플레이어의 환경설정을 저장할 수 있습니다. PlayerPref는 프로젝트와 별도로 디바이스 어딘가에 저장됩니다. 정확한 위치는 운영 체제에 따라 다르지만 일반적으로 운영 체제에서 전 세계적으로 액세스하고 관리할 수 있는 곳입니다. 저장된 데이터는 단순한 키-값 쌍으로 구성됩니다. 접근이 쉽기 때문에 열어보고 수정하려는 사용자로부터 안전하지 않으며, 프로젝트 외부에 저장되고 OS에서 관리하므로 실수로 삭제할 수도 있습니다.
플레이어프레프는 비교적 구현하기 쉽고 몇 줄의 코드만 있으면 되지만, 플로트, 인트, 스트링 타입 값만 지원하므로 크고 복잡한 오브젝트를 직렬화하기 어렵습니다. 의지가 있는 사용자라면 저장된 데이터를 이러한 기본 유형 중 하나로 표시되는 형식으로 변환하여 이 제한을 극복할 수 있지만, 데이터를 저장하는 더 나은 도구가 있으므로 권장하지 않습니다.
public void SavePrefs()
{
PlayerPrefs.SetInt("Volume", 50);
PlayerPrefs.Save();
}
public void LoadPrefs()
{
int volume = PlayerPrefs.GetInt("Volume", 0);
}
마지막으로, 각 Unity 애플리케이션은 모든 PlayerPref를 단일 파일에 저장하기 때문에 여러 개의 저장 파일이나 클라우드 저장을 처리하는 데 적합하지 않으며, 두 가지 모두 다른 위치에서 저장 데이터를 저장하고 수신해야 합니다.
JSON은 사람이 읽을 수 있는 데이터 형식입니다. 즉, 사람과 기계가 모두 쉽게 이해할 수 있다는 장점이 있는 동시에 단점도 있습니다. 저장된 데이터를 읽고 이해할 수 있으면 디버깅하거나 테스트 목적으로 새로운 저장 데이터를 생성하기가 훨씬 쉬워지지만, 다른 한편으로는 플레이어도 데이터를 읽고 수정하기가 쉽습니다. 데이터를 읽고 변경할 수 있는 기능은 모딩을 지원하는 경우 유용하지만 부정 행위를 방지하려는 경우 오히려 해가 됩니다. 이러한 우려 외에도 JSON은 텍스트 기반 형식이기 때문에 기계가 구문 분석하는 데 더 많은 비용이 듭니다. 즉, 바이너리 대체 방식보다 읽기 속도가 느리고 메모리를 더 많이 사용합니다. 따라서 데이터가 많은 경우 텍스트 기반이 아닌 옵션을 고려할 수 있습니다. 모든 사용 사례는 다르며, 이러한 절충점 때문에 개발자는 다양한 데이터 형식을 만들게 됩니다.
JSON은 표준화되어 다양한 애플리케이션에서 널리 사용되고 있습니다. 결과적으로 모든 플랫폼에서 이를 강력하게 지원하므로 크로스 플랫폼 게임을 제작할 때 유용합니다. JSON은 웹 브라우저용 통신 프로토콜로 개발되었기 때문에 본질적으로 네트워크를 통해 데이터를 전송하는 데 적합합니다. 이 때문에 JSON은 서버 백엔드에서 데이터를 주고받는 데 탁월합니다.
JsonUtility는 JSON 데이터를 직렬화 및 역직렬화하기 위한 유니티의 빌트인 API입니다. 플레이어 프리프와 마찬가지로 비교적 쉽게 구현할 수 있습니다. 하지만 PlayerPref와 달리 JSON 데이터는 파일이나 네트워크를 통해 직접 저장해야 합니다. 데이터 저장소를 직접 처리하면 각 파일을 다른 위치에 저장할 수 있으므로 여러 개의 저장 파일을 쉽게 관리할 수 있습니다. 이 작업을 더 쉽게 하기 위해 이 예제 리포지토리에서 사용할 수 있는 기본 파일 관리자를 작성했습니다.
한 가지 중요한 점은 JsonUtility가 완전한 기능을 갖춘 JSON 구현이 아니라는 점입니다. JSON 데이터 작업에 익숙하다면 특정 기능에 대한 지원이 부족하다는 것을 알 수 있습니다. 다양한 JSON 솔루션의 성능을 비교하는 데 관심이 있다면 이 벤치마킹 프로젝트를 시도해 보세요. 가능하면 대상 기기에서 테스트하는 것이 가장 좋습니다.
즉, 인스펙터에서 필드를 직렬화할 수 없는 경우 JSON으로 직렬화할 수 없는 것과 같은 제약 조건이 내부 Unity 직렬화기와 JsonUtility를 제한합니다. 이러한 제한 사항을 해결하려면 모든 저장 데이터를 보관하는 일반 오래된 데이터 유형 (또는 POD)을 만들 수 있습니다. 저장할 때가 되면 런타임 유형에서 POD로 데이터를 전송하고 디스크에 저장합니다. 필요한 경우 커스텀 직렬화 콜백을 생성하여 Unity의 직렬화 프로그램이 기본적으로 지원하지 않는 유형을 지원할 수도 있습니다.
JsonUtility와 관련해서는 EditorJsonUtility가 또 다른 유용한 도구입니다. JsonUtility는 모든 MonoBehaviour 또는 스크립터블 오브젝트 기반 오브젝트에서 작동하는 반면, EditorJsonUtility는 모든 Unity 엔진 유형에서 작동합니다. 따라서 Unity 에디터에서 오브젝트의 JSON 표현을 만들거나 다른 방향으로 전환하여 JSON 파일에서 에셋을 만들 수 있습니다.
기본 제공 직렬화 옵션 외에도 사용할 수 있는 다른 외부 라이브러리도 있습니다. 가독성을 위해 특별히 텍스트 기반 형식을 사용해야 하는 경우가 아니라면 바이너리 기반 직렬화기를 사용하는 것이 가장 좋습니다:
바이너리 도구
- MessagePack은 효율적인 바이너리 직렬화 프로그램입니다. 성능이 뛰어나고 비교적 사용하기 쉽습니다. JSON과 마찬가지로 거의 모든 플랫폼에서 사용할 수 있으므로 네트워크를 통해 데이터를 전송하여 백엔드 서버와 통신하는 데 사용할 수 있습니다. 자세한 내용은 여기에서 확인할 수 있습니다.
- 또 다른 유사한 바이너리 직렬화기인 ProtoBuf와 Protobuf-net이 있습니다. 또한 빠르고 효율적입니다. Google은 XML과 같은 기존 형식에 대한 성능 좋은 대안으로 이 형식을 개발했습니다. JSON 및 MessagePack과 마찬가지로 네트워크를 통한 통신에도 적합합니다.
- BinaryFormatter는 오브젝트를 바이너리 형식으로 직접 저장할 수 있는 DotNet 라이브러리입니다. 그러나 BinaryFormatter는 위험한 보안 취약점이 있으므로 사용하지 않아야 합니다. 반복합니다, BinaryFormatter를 사용하지 마세요. 보안 위험에 대한 자세한 내용은 여기에서 확인하세요.
텍스트 도구
- EasySave는 유니티 에셋 스토어에서 많은 지원을 받고 있는 인기 플러그인입니다. 코드를 작성하지 않고도 모든 데이터를 저장할 수 있어 초보자에게 매우 유용합니다. 또한 강력하고 유연한 API를 갖추고 있어 고급 사용자에게도 이상적입니다. 무료는 아니지만 모든 기능을 갖춘 기본 제공 솔루션을 찾고 있다면 그만한 가치가 있습니다.
- JSON.Net은 모든 닷넷 플랫폼을 위한 무료 오픈 소스 JSON 구현입니다. 기본 제공 JsonUtility와 달리 모든 기능을 갖추고 있습니다. 하지만 내장된 JsonUtility에 비해 성능이 현저히 떨어지기 때문에 비용이 발생합니다. 표준 버전은 Unity의 모든 플랫폼을 지원하지는 않지만, Unity 에셋 스토어에서 지원을 추가하는 수정 버전을 사용할 수 있습니다.
- XML은 대체 데이터 형식입니다. JSON과 마찬가지로 사람이 비교적 쉽게 읽을 수 있으며 네임스페이스와 같이 특정 애플리케이션에 유용할 수 있는 몇 가지 기능이 있습니다. 닷넷은 XML을 기본적으로 지원합니다.
보안이라고 하면 대부분의 사람들은 암호화를 먼저 떠올립니다. 하지만 플레이어의 기기에 로컬로 데이터를 저장하는 경우 암호화는 비교적 쉽게 극복할 수 있습니다. 암호화를 해제하지 않고도 사용자는 무료로 제공되는 도구를 사용하여 메모리에서 직접 데이터를 조작할 수 있습니다. 즉, 로컬에 저장된 모든 것은 신뢰할 수 없다고 가정하는 것이 안전합니다.
진정한 보안이 필요하다면 사용자가 데이터를 수정할 수 없는 서버에 데이터를 보관하는 것이 가장 좋습니다. 이 기능이 작동하려면 사용자가 여전히 데이터를 조작할 수 있으므로 애플리케이션이 데이터를 서버로 직접 보내지 않아야 합니다. 대신 애플리케이션은 서버에 명령을 전송하고 서버가 데이터를 변경한 다음 결과를 애플리케이션으로 다시 전송할 수 있습니다. 따라서 데이터 보안이 중요하다면 프로젝트 아키텍처에 영향을 미치므로 가능한 한 빨리 파악하는 것이 가장 좋습니다.
직렬화에 대한 자세한 내용은 매뉴얼 페이지를 참조하세요. 이 기능이 실제로 작동하는 모습을 보고 싶으시다면 함께 제공되는 Unite Now 세션 을 확인하세요.