본문 바로가기
유니티 이야기

[Unity] 게임 데이터 바이너리 파일로 저장하기

by novices 2022. 8. 25.

본 포스팅은 게임 데이터를 저장할 때 일반 사용자가 변조할 수 없도록 바이너리로 저장하는 방법을 알아보겠습니다.

 

예시로 스타크래프트의 마린의 체력과 킬 데이터를 저장해보겠습니다.

스타크래프트-마린-gif
starcraft marine 이미지

 

 

1. 스크립트 구성

MarineData.cs (마린의 정보를 담을 클래스)

SaveManager.cs (마린의 데이터를 바이너리로 디스크에 읽고 쓰는 기능을 하는 클래스)

Marine.cs (마린 유닛 조작 클래스) - 해당 스크립트에서 파일을 저장하고 읽어옵니다.

 

▶ MarineData.cs

MarineData는 단순히 저장할 데이터 값을 한 곳에 몰아서 편하게 저장하기 위한 클래스입니다.

마린의 데이터를 저장할 때 인스턴스화(메모리에 새로 찍어내고)하고 생성자를 통해 값을 전달합니다. 

[System.Serializable]
public class MarineData
{
    public int health, kill;
    // 인스턴스화 된 마린을 입력으로 받는다.
    public MarineData(Marine marine) // 생성자
    {
        health = marine.health; kill = marine.kill;
    }
}

 

SaveManager.cs

이번 포스팅의 핵심인 저장하고 로드하는 클래스입니다. 경로를 지정하여 스트림을 생성하고 데이터와 함께 바이너리로 저장하고 읽어올 때는 해당 경로에 파일 존재 여부를 확인해 저장 처리의 역순으로 저장된 파일을 복원하여 리턴합니다. 저장 경로를 만들 때 사용된 Application.persistentDataPath는 유니티에서 제공하는 운영체제별 특정 디렉터리의 경로를 뜻합니다. 자세한 경로 확인은 공식 API 문서에서 확인하시면 됩니다. 

using System.IO; // 디스크 읽기 쓰기를 위한 using 선언
using System.Runtime.Serialization.Formatters.Binary; // BinaryFormatter 클래스 위치
using UnityEngine; // Application.persistentDataPath 사용을 위한 선언

public static class SaveManager
{
    public static void SaveMarine (Marine marine)
    {
        BinaryFormatter binaryFormatter = new BinaryFormatter();

        string saveFileName = "MarineData"; // 저장파일 이름
        string savePath = Application.persistentDataPath + "/" + saveFileName; 

        FileStream fileStream = new FileStream(savePath, FileMode.Create);
        MarineData marineData = new MarineData(marine);

        binaryFormatter.Serialize(fileStream, marineData);
        fileStream.Close();
    }

    public static MarineData LoadMarine ()
    {
        string saveFileName = "MarineData";
        string loadPath = Application.persistentDataPath + "/" + saveFileName;

        if(File.Exists(loadPath))
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            FileStream fileStream = new FileStream(loadPath, FileMode.Open);

            MarineData marineData = binaryFormatter.Deserialize(fileStream) as MarineData;
            fileStream.Close();

            return marineData;
        }
        else
        {
            // loadPath경로에 saveFileName이름의 파일이 없다면 null을 리턴
            return null;
        }
    }
}

 

Marine.cs

예제의 단순화를 위해 Marine클래스에 필요한 변수만 추가하였습니다. 더 많은 정보를 저장한다면 MarineData와 Marine클래스의 변수를 추가하면 됩니다. Marine클래스 내에서 SaveManager에 접근하여 데이터를 저장하고 읽어옵니다.

using UnityEngine;

public class Marine : MonoBehaviour
{
    public int health = 40;
    public int kill = 7;

    // 저장 할 때 실행 할 함수 
    public void SaveData() {SaveManager.SaveMarine(this);}
    // 로드 할 때 실행할 함수
    public void LoadData() 
    {
        MarineData marineData = SaveManager.LoadMarine();

        if(marineData == null) // 저장된 데이터가 없을 경우 함수를 종료한다.
            return;

        health = marineData.health;
        kill = marineData.kill;
    }
}

 

 

2. 실행 결과

Marine 클래스의 Awake 함수에 SaveData함수를 실행하여 결과를 확인해 보았습니다.

Application.persistentDataPath에 정상적으로 파일이 생성되었고 파일 내용은 이진화되었습니다.

다만 클래스명이나 변수가 보입니다.. 코딩하시는 분 입장에서는 어떤 클래스인지 추측이 가능할 것 같아서

클래스명이나 변수명을 추측 불가능하게 변경하였습니다. 

 

생성된-세이브파일
생성된 파일

 

이진화된-세이브파일-내용
binary 파일내용

 

 

댓글