JSON이란 자바스크립트에 뿌리를 두고 있는 경량의 데이터 포맷입니다. 데이터가 표현될 때 클래스나 배열까지 표현이 가능하고 데이터 자체가 텍스트로 이루어져 있어 이해하기 쉽고 독립적이어서 게임 데이터를 저장할 때 자주 사용됩니다. 제가 사용하면서 느낀 장점은 데이터를 개별적으로 저장하는 번거로움이 없고 데이터 구조를 통으로 저장하고 읽어올 수 있으며 관련 유틸이 잘 만들어져 있어서 쉽게 사용할 수 있었습니다.
이런 이유로 대부분 프로그래밍 언어에서 Json 직렬화는 지원하고 있어 다른 언어 간에도 데이터를 이동시킬 수 있는 장점이 있습니다. 단점은 파일 자체가 텍스트고 체계가 있다 보니 파일을 열어서 읽어보면 내용 자체를 이해하고 수정이 가능합니다. 관련 기능을 유니티 API 문서를 참고해서 작성해 보았습니다.
1. Json 저장 및 읽어오기 기능 만들기
기능을 테스트하기 위해 3개의 스크립트를 작성했습니다.
- PlayerData.cs (저장을 위한 데이터 구조)
- JsonSerialize.cs (Json 저장 및 읽어오기 기능)
- Player.cs (저장할 데이터를 가지고 있는 클래스)
▶ PlayerData.cs
플레이어의 게임 데이터중 저장할 값만 구조화한 클래스입니다.
[System.Serializable]
public class PlayerData
{
public int level, power, defence;
public PlayerData(Player player)
{
level = player.level;
power = player.power;
defence = player.defence;
}
}
▶ JsonSerialize.cs
주 기능이 작성된 곳입니다. 저장 부분은 PlayerData를 메모리에 하나 찍어내 데이터를 담고 JsonUtillity로 문자열 변환하여 정해진 파일 경로에 저장합니다. 읽어 올 때는 역순으로 처리되는데 JsonUtility.FromJson<PlayerData> (jsonFromFile); 구문이 메모리를 PlayerData를 인스턴스화 하는 것이 특이하게 느껴집니다. 정상적으로 파싱 된 데이터를 player의 변수에 할당합니다.
using System.IO;
using UnityEngine;
public static class JsonSerialize
{
// 세이브 Json
public static void SavePlayerToJson(Player player)
{
string fileName = Path.Combine(Application.persistentDataPath + "/PlayerData.json");
// 저장 된 파일이 있으면 삭제
if(File.Exists (fileName))
File.Delete (fileName);
// PlayerData를 메모리에 하나찍어내고 생성자에 player인스턴스를 전달한다.
PlayerData data = new PlayerData(player);
// data를 json으로 변환
string json = JsonUtility.ToJson (data);
//디스크에 쓰기
File.WriteAllText (fileName, json);
}
// 로드 Json
public static void LoadPlayerFromJson(Player player)
{
string fileName = Path.Combine(Application.persistentDataPath + "/PlayerData.json");
//파일이 있을 때 만 로드한다.
if (File.Exists (fileName))
{
//디스크에서 읽어와 string 변수에 담는다.
string jsonFromFile = File.ReadAllText (fileName);
// Json유틸리티로 PlayerData형태로 복원한다.
PlayerData data = JsonUtility.FromJson<PlayerData> (jsonFromFile);
//복원된 data로 player의 데이터에 저장한다.
player.level = data.level;
player.power = data.power;
player.defence = data.defence;
}
}
}
▶ Player.cs
기능 테스트를 실행하기 위한 데이터를 가지고 있고 저장과 읽어오기에 트리거 역할을 하는 클래스입니다.
using UnityEngine;
public class Player : MonoBehaviour
{
public int level, power, defence;
void Start()
{
level = 10; power = 30; defence = 5;
JsonSerialize.SavePlayerToJson(this);
}
public void Attack(){}
public void Move(){}
public void Damage(){}
}
2. 저장 및 읽어오기 테스트
위의 Player.cs를 빈 오브젝트에 붙어 에디터에서 실행시킨 후 저장된 파일을 메모장으로 열어보았습니다. 기능 자체는 정상적으로 작동하지만 저장된 내용이 너무 적나라하게 드러납니다.. 저장된 값은 쉽게 조작 가능하여 사용하기에는 무리가 있어 보입니다.
이런 부분을 보완하고자 json으로 변환된 텍스트를 ut8로 암호화해 보았습니다.
3. 암호화 (utf8)
완벽한 암호화는 아니지만 일반 사용자 입장에서는 접근하기는 힘듭니다. 코드는 JsonSerialize 클래스의 저장 함수에 UTF-8 인코딩하는 부분과 로드 함수에 디코딩 부분만 추가했습니다.
▶ JsonSerialize.cs (암호화 코드 추가)
초기 코드랑 다른 점은 Json 형태로 파싱 된 문자열을 저장하기 전에 UTF-8 인코딩하여 저장하는 과정과 읽어온 후 디코딩하는 과정이 추가되었습니다.
using System.IO;
using UnityEngine;
public static class JsonSerialize
{
public static void SavePlayerToJson(Player player)
{
string fileName = Path.Combine(Application.persistentDataPath + "/PlayerData.json");
if(File.Exists (fileName))
File.Delete (fileName);
PlayerData data = new PlayerData(player);
string json = JsonUtility.ToJson (data);
// 완성된 json string 문자열을 8비트 부호없는 정수로 변환
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(json);
// 변환된 바이트배열을 base-64 인코딩된 문자열로 변환
string encodedJson = System.Convert.ToBase64String(bytes);
// 변환된 값을 저장
File.WriteAllText (fileName, encodedJson);
}
public static void LoadPlayerFromJson(Player player)
{
string fileName = Path.Combine(Application.persistentDataPath + "/PlayerData.json");
if (File.Exists (fileName))
{
// json으로 저장된 문자열을 로드한다.
string jsonFromFile = File.ReadAllText (fileName);
// 읽어온 base-64 인코딩 문자열을 바이트배열로 변환
byte[] bytes = System.Convert.FromBase64String(jsonFromFile);
// 8비트 부호없는 정수를 json 문자열로 변환
string decodedJson = System.Text.Encoding.UTF8.GetString(bytes);
PlayerData data = JsonUtility.FromJson<PlayerData> (decodedJson);
player.level = data.level;
player.power = data.power;
player.defence = data.defence;
}
}
}
4. 암호화된 Json 파일 내용 확인
게임 데이터를 저장할 때 문자열을 utf-8로 인코딩하는 방법 외로 binary로 저장하는 방법도 자주 사용하고 있습니다.
UTF-8 변환에 대해서는 .NET API 문서를 참고하였습니다.
'유니티 이야기' 카테고리의 다른 글
[Unity] 2022 Codeless 인앱 결재(IAP) Tutorial (1) (0) | 2022.08.29 |
---|---|
[Unity] 대량의 엑셀데이터 유니티 인스턴스로 밀어넣기 (0) | 2022.08.28 |
[Unity] CultureInfo를 통해 언어 설정 하기 (0) | 2022.08.26 |
[Unity] 게임 데이터 바이너리 파일로 저장하기 (0) | 2022.08.25 |
[Unity] 현지화를 위한 게임 구동 시 언어를 자동으로 설정하는 방법 (0) | 2022.08.24 |
댓글