🐧 들어가기 앞서

새로운 팀이 구성됐다!

다양하게 팀을 구성하는 내일배움캠프 시스템이 좋다.

새로운 유형의 사람을 만나보는 것도 굉장히 중요한 경험이다.

그룹에 자연스럽게 녹아들 수 있는 사람이 되어보자!


유튜브 노마드 코더의 니콜라스님이 알려주신 학습법이다!

https://youtu.be/qrpyswoATQ8?si=nHcIX_fOSdAJJ5_-


🐧 오늘 배운 것

  1. JSON 직렬화 & 역직렬화 (게임 데이터 저장)

🐧 기억할 것 & 진행

JSON 직렬화 & 역직렬화 (게임 데이터 저장)

https://github.com/Munch310/SpartaDungeon/wiki/7.-%EC%A3%BC%EC%9A%94-%EA%B8%B0%EB%8A%A5-%EC%86%8C%EA%B0%9C-(%ED%9C%B4%EC%8B%9D-&-%EA%B2%8C%EC%9E%84-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%80%EC%9E%A5)

README.md에 자세히 설명했다.

그러나 한번 더 설명! ㅡ


진행중인 데이터 (플레이어 스탯, 아이템 정보 등)을 저장하는 방법은 여러가지가 있다.

  1. CSV
  2. JSON
  3. XML
  4. SQL DB
  5. Excel
    etc.

각자 장단점이 있으며, 최종 저장 방법은 데이터 베이스 저장 방식이라고 생각한다.

JSON?
JavaScript Object Notation, 데이터 교환을 위한 경량의 텍스트 기반 형식이다.
https://ko.wikipedia.org/wiki/JSON

내일배움캠프 튜터님께서 C# 팀 과제에 데이터를 저장하는 요구사항을 JSON으로 정하셨다.

이유를 생각해보니,

  1. XML에 비해 가독성이 좋다.
    아래 코드는 손님 세명의 이름을 각각 형식으로 표현한 예시다.
    XML은 트리 패턴을 사용하지만, JSON은 키-값 쌍을 사용한다.
    JSON이 가독성이 더 좋음을 확인할 수 있다!
  • JSON
{"guests":[

  { "firstName":"John", "lastName":"Doe" },

  { "firstName":"María", "lastName":"García" },

  { "firstName":"Nikki", "lastName":"Wolf" }

]}
  • XML
<guests>

  <guest>

    <firstName>John</firstName> <lastName>Doe</lastName>

  </guest>

  <guest>

    <firstName>María</firstName> <lastName>García</lastName>

  </guest>

  <guest>

    <firstName>Nikki</firstName> <lastName>Wolf</lastName>

  </guest>

</guests>
  1. XML에 비해 JSON이 보안성이 뛰어나다.
    XML은 JSON에 비해 무단 수정에 취약하다.
    -> XXE, XML External Entity = 악의적인 구문 삽입이 가능하다.

물론 XML도 JSON에 비해 장점이 있다!
본인의 코드에 잘 어울리는 것으로 정하자.


그렇다면 직렬화, 역직렬화는 무엇일까?

직렬화(Serialize)

직렬화는 디지털 정보를 수집하고 보관하는 곳 (데이터 스토리지)에서 자료 구조나 오브젝트 상태를 동일 또는 다른 컴퓨터 환경에 저장하고 나중에 재구성할 수 있는 형식으로 변환하는 과정이다.

즉!

레고 조각을 정리해서 상자에 넣는 것 처럼, 컴퓨터도 데이터를 필요한 모양으로 정리해서 파일에 넣어둔다.

나중에 필요할 때, 그 데이터를 꺼내서 다시 레고 조각처럼 조립할 수 있게 만들어주는 과정이다.

컴퓨터가 데이터를 효율적으로 다루고 저장할 수 있게 도와준다.

그렇다면, 적용해보자!

(여기 글에서는 Newtonsoft.Json 사용방법을 소개한다. 다음 프로젝트에서는 System.Text.Json를 사용하겠다!)
( 두 방식의 차이는 - https://learn.microsoft.com/ko-kr/dotnet/standard/serialization/system-text-json/migrate-from-newtonsoft?pivots=dotnet-7-0#differences-in-default-behavior

  1. 우선 Visual Studio에서 프로젝트 - NuGet 패키지 관리를 선택한다.
  1. NewtonsSoft.Json 패키지를 검색하여 설치한다.

  2. using 지시문을 작성한다.

세팅은 끝!


이제 코드를 구현해보겠다.

내가 원하는 메서드 안에 데이터 저장 기능을 구현하면 된다.

나는 휴식을 취하면, 데이터가 저장 될 수 있게 구현했다.

// Json 직렬화
                    string _fileName = "playerStat.json";
                    string _itemFileName = "itemData.json";
                    // 데이터 경로 저장. (C드라이브, Documents)
                    string _userDocumentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                    string _filePath = Path.Combine(_userDocumentsFolder, _fileName);
                    string _itemFilePath = Path.Combine(_userDocumentsFolder, _itemFileName);

                    string _playerJson = JsonConvert.SerializeObject(_playerStat, Formatting.Indented);
                    string _itemJson = JsonConvert.SerializeObject(_itemsInDatabase, Formatting.Indented);
                    File.WriteAllText(_filePath, _playerJson);
                    File.WriteAllText(_itemFilePath, _itemJson);
                    Console.WriteLine("저장이 완료되었습니다.");

  • 파일 이름 설정
string _fileName = "playerStat.json";

JSON 파일 네임을 원하는 대로 설정할 수 있다.

  • 파일 경로 설정
string _userDocumentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

JSON 파일을 사용자의 Document("C:\Users\Username\Documents")에 저장하는 기능이다.
만약 이런 과정을 거치지 않으면

G:\Workplace\CsharpLec\SpartaDungeon\SpartaDungeon\SpartaDungeon\SpartaDungeon\bin\Debug\net6.0 이런식으로 해당 파일이 거의 찾을 수 없게 된다..

  • 파일 경로 + 이름
string _filePath = Path.Combine(_userDocumentsFolder, _fileName);

_userDocumentsFolder가 "C:\Users\Username\Documents"이고
_fileName이 "playerStat.json"일 경우,
Path.Combine(_userDocumentsFolder, _fileName)은
"C:\Users\Username\Documents\playerStat.json"와 같은 경로를 생성해준다.

  • 직렬화 코드
  1. _playerStat: 이 변수는 PlayerStat 클래스의 인스턴스를 가리키며, 이 클래스의 객체가 JSON 형식으로 변환된다. 즉, 플레이어의 게임 데이터를 담고 있는 객체다.

  2. JsonConvert.SerializeObject: 이 메서드는 Newtonsoft.Json 라이브러리에서 제공되며, C# 객체를 JSON 형식의 문자열로 변환한다. SerializeObject 메서드는 첫 번째 인자로 직렬화할 객체를 받고, 필요한 경우 두 번째 인자로 형식 지정 옵션을 전달할 수 있다.

  3. Formatting.Indented: 이는 형식을 지정하는 옵션으로, Formatting.Indented를 사용하면 JSON 문자열이 들여쓰기를 포함하여 가독성을 높인 형태로 생성된다.

  • 경로에 텍스트 저장
    _filePath에 지정된 경로에 _playerJson에 저장된 JSON 형식의 문자열을 쓴다.
    즉, _playerStat 객체를 JSON 형식으로 직렬화한 결과를 해당 파일에 저장하는 역할을 한다.

역직렬화(DeSerialize)

직렬화의 반대 개념으로, 저장된 디지털 정보나 데이터를 다시 컴퓨터의 메모리나 프로그램에서 사용할 수 있는 객체나 자료 구조로 변환하는 과정을 말한다.

즉!

나중에 그 데이터가 필요할 때,

마치 레고 조립을 하는 것처럼 데이터 조각들을 꺼내와서 다시 원래 모양으로 조립하는 과정이 바로 역직렬화다.

이렇게 조립된 데이터는 컴퓨터가 다시 효율적으로 활용할 수 있게 도와준다.

그렇다면 적용해보자!


우선 플레이어 정보와 아이템을 역직렬화 하는 메서드를 생성했다.

메인 게임을 실행하기 전, 역직렬화를 통해 저장된 데이터가 있으면 불러오며,

저장된 데이터가 없으면, 플레이어 정보를 설정하는 화면, 아이템 데이터를 초기화 해준다.

 // 역 직렬화
        static void LoadGameData()
        {
            string _playerFileName = "playerStat.json";
            string _itemFileName = "itemData.json";
            // 데이터 경로 불러오기. (C드라이브, Documents)
            string _userDocumentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

            // 플레이어 데이터 로드
            string _playerFilePath = Path.Combine(_userDocumentsFolder, _playerFileName);
            if (File.Exists(_playerFilePath))
            {
                string _playerJson = File.ReadAllText(_playerFilePath);
                _playerStat = JsonConvert.DeserializeObject<PlayerStat>(_playerJson);
                Console.WriteLine("플레이어 데이터를 불러왔습니다.");
            }
            else
            {
                Console.WriteLine("저장된 플레이어 데이터가 없습니다.");
                Thread.Sleep(300);
                PlayerDataSet();
            }

            // 아이템 데이터 로드
            string _itemFilePath = Path.Combine(_userDocumentsFolder, _itemFileName);
            if (File.Exists(_itemFilePath))
            {
                string _itemJson = File.ReadAllText(_itemFilePath);
                _itemsInDatabase = JsonConvert.DeserializeObject<List<ItemData>>(_itemJson);
                Console.WriteLine("아이템 데이터를 불러왔습니다.");
            }
            else
            {
                Console.WriteLine("저장된 아이템 데이터가 없습니다.");
                _itemsInDatabase = new List<ItemData>(); // 빈 리스트로 초기화
                InitItemDatabase();
            }
        }
  • 불러오기
if (File.Exists(_playerFilePath))
            {
                string _playerJson = File.ReadAllText(_playerFilePath);
                _playerStat = JsonConvert.DeserializeObject<PlayerStat>(_playerJson);
                Console.WriteLine("플레이어 데이터를 불러왔습니다.");
            }

해당 구문을 보면, if문에서 해당 경로에 파일이 존재하는지 확인한다.

이후, ReadAllText로 텍스트 내용을 문자열로 읽어온다.

읽어온 JSON 문자열인 palyerJson을 역직렬화한다.

🐧 게임에 구현한다면?

저장된 데이터가 없음

  1. 저장된 데이터가 없으면, 아래와 같이 출력한다.

  2. 닉네임을 설정하는 메시지가 출력된다.

  3. 닉네임을 입력하면, 저장된 아이템 데이터가 없기 때문에 저장된 아이템이 없다는 메시지를 출력한다.

  4. 저장 전, 인벤토리 상태다.

  5. 저장 전, 플레이어 스탯 상태다.

  6. 저장은 휴식을 통해 진행한다.

저장된 데이터 있음

  1. 저장된 데이터가 있으면, 바로 불러오고 메시지를 출력한다.

  2. 저장 후, 플레이어의 스탯 상태다.

  3. 저장 후, 인벤토리 상태다.

  4. 문서 폴더에 파일이 저장된 것을 확인할 수 있다.

  5. 아이템 데이터 JSON 파일이다.

  6. 플레이어 스탯 JSON 파일이다.


🐧 내일 할 일

콘솔을 어떻게 꾸밀 수 있을지 고민해보고 디자인해봐야겠다.

또한, 다른 팀원이 작성해 준 코드를 확인하며, 어떤 데이터를 저장해야할지,

Newtonsoft.Json 을 System.Text.Json로 바꾸는 방법을 공부해야겠다.

Reference

0개의 댓글