Unity_본캠프

[내일배움캠프 10일차]TextRPG 제작기 5

티백고래 2025. 4. 18. 22:48

0. 어제 해놓은 짓

어제 TIL을 작성해놓고, 코드를 더 만지작거렸다.

그 결과, 다음과 같은 기능을 형성했다.

 

1. 던전 추가(신비의 숲, 마굴-권장 방어력 40, 200의 하드난이도 던전)

2. Clear()기능 추가: 마을>상점/여관>마을 등 완전히 별개의 장면으로 넘어갈 때마다 사용하는 Clear기능을 추가했다.

    계속 진행하려면 아무 키나 누르도록 하여, 장면이 넘어감을 알림과 동시에 깔끔하게 콘솔창을 정리할 수 있도록 만들었다.

3. 여관 아이템 추가: 여관-식사 파트에서 사용할 아이템 리스트를 형성했다. 도입은 아직.

 

1. 오늘의 할 일

 

 

저장/불러오기 기능 추가

여관-식사 기능 추가(소량의 돈을 주고, 약간의 HP를 회복 가능)

아이템-무기/방어구 구분 (가능하다면!)

 

2. 작업 개시🛠️

1. 저장/불러오기 기능

저장/불러오기, 즉 Save/Load.

제작 방법은 제각각인 것 같은데, 나는 json 파일을 이용했다.

 

막연해서 사실 안 넣을까 하던 기능이었지만…하지만…

언젠가는 써야하는 기능이기 때문에, 이번 기회에 시도해보도록 했다.

 

    1. 일단 json패키지를 설치한다.

도구>NuGet 패키지 관리자>솔루션용 NeGet 패키지 관리...로 들어간다.

 

설치가 안되어 있으면 찾아보기>json을 검색한다.

난 그냥 가장 상단에 있는 걸 받았다.

해당 패키지를 설치할 프로젝트를 선택하고 설치하면 끝.

오래 걸리지 않고, 그러면 준비가 끝난다.

 

이제 게임 save/load 로직만 짜주면 된다.

        //게임 저장
        public static void SaveGame(Player player)
        {
            string saveData = JsonSerializer.Serialize(player);
            File.WriteAllText("savegame.json", saveData);
            Console.WriteLine("게임이 저장되었습니다.");
        }

        //게임 불러오기
        public static Player LoadGame(Player player)
        {
            if (File.Exists("savegame.json"))
            {
                string saveData = File.ReadAllText("savegame.json");
                return JsonSerializer.Deserialize<Player>(saveData);
            }
            Console.WriteLine("저장된 게임이 없습니다.");
            return null;
        }

 

(코드 블럭 기능을 이제야 발견했다.)

 

일단 이러면 된다니까 썼는데.

saveData라는 곳에 player라는 데이터를 심어서, savegame이라는 곳에 집어 넣는 구조 같다.

반대로 불러올 때는, savegame.json의 존재 여부를 확인하고, 존재하면 해당 파일을 열어서 적용하고, 없으면 즉시 시작하는 상태로 보인다.

 

그럼 실제로도 그런지 한 번 구동 시켜봐야지.

 

1. 저장데이터 없음-새로하기

아직 아무것도 생성하지 않았고, 새로하기 버튼을 눌렀을 때다.

당연하지만 일반적인 진행과 같으므로 큰 문제 없이 동작한다.

 

2. 저장데이터 없음-불러오기

반환값이 null이라 그냥 바로 픽 꺼져버린다.

불러오기를 했는데 값이 없다면 새 게임을 시작하도록 만들어야 한다.

 

 

 

기존에 Main에 있던 이름/직업 선택 함수를 따로 분리하고, StartNewGame(); 을 추가하여 옮겼다.

그럼 다시 재시도 해보자.

 

저장된 게임이 확인되지 않자, 바로 새로운 게임을 시작해준다! (와!)

그럼 이제 저장도 제대로 되는지 확인하러 가자.

 

3. 저장데이터 있음-불러오기

 

일단 설정한 대로라면, '플레이어'정보는 그대로 저장되어야 한다.

세이브는 현재 인벤토리-일기로 제작해둔 상태이다. (차후 던전 진입 전, 여관-숙박에서도 저장할 수 있게 할 것이다)

 

1. 상점에서 아이템을 구매

2. 던전 클리어

3. 세이브

4. 콘솔 종료 후 로드

 

이 순서로 확인해볼 것이다.

 

추정되는 문제

: 구매한 아이템 리스트가 사라짐-그에 따른 상점 아이템 구매여부 초기화

 

1~3을 진행하는 과정

더보기

1. 아이템 구매-수련자의 경갑 (실수로 2번에서 사용하던 콘솔을 닫아버렸다)

 

장착도 정상적으로 된 것을 확인했다.

 

 

2. 던전 클리어

 

 

 바위산 던전을 선택하고, 클리어한 모습.

(*권장 방어력보다 낮을 수록, 클리어 확률이 더 줄어들도록 만들어야 할 것 같다.)

 

3. 세이브

이제 다시 마을로가서, 인벤토리를 열고 저장한다.

 (*지문과 시스템 알림을 구분 짓도록 수정할 것.)

게임 종료 직전, 스탯을 확인해두고, 게임을 끈다.

 

 

이제 콘솔 종료 후 로드를 해볼 것이다.

과연 제대로 저장이 되었을까?

 

일단 폴더에는 savegame 파일이 생긴 것을 확인했다.

하지만 다시 실행해서, 불러오기를 택하자…

 

나를 마주한 현실

 

아이고 맙소사

처음보는 놈이 잘 될 리가 없지.

 

json은 진짜 처음 쓰는 것이기 때문에, 해결방법은 별도로 찾아보아야 한다.

내가 오류코드 보고 고칠 수 있으면 여기 없지....

내가 읽을 수 있는 건 가장 마지막 두 줄 뿐이야...

 

이렇게 된 이상 내 주먹구구로 해결할 수 없다.

하지만 Visual Studio 2022 에는 멀리 가지 않고도 날 도와줄 친구가 있다.

 

 

가라 Copilot! (aka. GPT -4o)

 

이렇게 오류 코드를 보여주면, 현재 내 코드를 분석해서 왜 해당 오류가 났는지 확인하고, 해결 방법도 제시해준다.

1. 필드를 프로퍼티로 바꾸던지, (권장)

2. 필드를 포함해서 불러오도록 하던지, (필드 유지)

3. 매개변수 없는 빈 생성자를 만들라고 한다.

권장 방법은 프로퍼티로 바꾸는 것이라고 한다. 하지만 코드가 크게 바뀌지 않는 건 필드를 포함해서 불러오는 것이다.

일단, 코드를 크게 변경할 필요가 없는 2번으로 해보고, 제대로 동작하는지 지켜보자.

 

2번 방법으로 적용한 LoadGame

 //게임 불러오기
 public static Player LoadGame(Player player)
 {
     if (File.Exists("savegame.json"))
     {
         string saveData = File.ReadAllText("savegame.json");
         var options = new JsonSerializerOptions
         {
             IncludeFields = true // 필드 포함
         };
         return JsonSerializer.Deserialize<Player>(saveData, options);
     }
     Console.WriteLine("저장된 게임이 없습니다.");
     
     StartNewGame();
     return null;
 }

 

 

 

결과

더보기

 

오, 이번에는 정상적으로 게임시작이 되었다!

 

그럼, 이제 다른 요소(스탯/아이템/상점/장비)가 정상적으로 보관되어 있는지 살펴보자.

그만 알아보자.

 

그런 와중에 상점 주인 아저씨는 아는 척을 해준다. (상점 방문 카운트는 그대로 저장된 모양이다...)

불러오기->게임 실행까지는 정상적으로 진행되었지만, 정작 중요한 요소(이름, 직업-그에 따른 스탯)들은 들어오지 않았다.

즉, StartNewGame() 에서 설정되는 이름/직업과 이로 인해 변화되야 하는 부분은 적용이 되지 않고, 생성자로 만든 초기 플레이어가 그대로 들어간 것이다.

 

그럼 1번 방법으로 수정을 해보자.

필드를 프로퍼티로 수정하라고 한다.

 

 

 

그래서 바꾸었고, 예정된 재앙을 마주했다.

소문자가 죄다 대문자로 바뀌어서 발생한 일이니, 빠르게 수정해주도록 하자...

 

휴.

그럼 다시 1. 새게임 2. 저장 3. 불러오기 를 해보자.

 

다시 확인작업 on

더보기

1. 일단 새 게임 생성

 이름과 스탯: 정상적으로 들어갔다.

 

2. 내부 수치 변화

 

 겸사겸사 실패 로직도 구경했다.

 

던전 하나도 추가로 돌아, 체력을 더 깎고, 레벨업도 시키고, 골드에도 변화를 주었다.

레벨업을 위해서 잠시 회복하고, 레벨업도 시켜줬다.

 

인벤토리에는 수련자의 경갑도 있어야 한다.

(*여기서 레벨업 시 공격력과 방어력 상승 배율을 1.2배로 올려야겠다는 생각을 했다. 8과 7인 궁수는 능력치가 하나도 안 올라간다.)

 

3. 저장

 

 

저장했으니, 나가서 확인해보자.

 

4. 불러오기

 

 진심인가?

 

 

이번에도 <실패>

뭐가 문제일까? savegame.json에 저장이 제대로 안됐나? 하고 json파일을 열어보았다.

 

아닌데, 이거 잘 있는데. 이상한데.

아무래도 생성되면서 new Player가 중간에 작동하는 모양이다.

혹시 LoadGame에 Player 매개변수를 넣은 게 문제일까? 나중에 Player 객체 반환 하잖아.

그래서 빼봤습니다.

 

저장데이터가 멀쩡한 걸 확인했으니, 수정 후 다시 불러오기를 해보는 걸로 확인해보자....

그래. 아니구나. 미안해.

그럼 여기서 불러온 player의 내용을 다시 player에게 할당해보자....

 

 

결과

 

으아아악 됐다

 

하지만, 당연하게도, 아이템 정보는 사라졌다. (저장한 건 플레이어 데이터 뿐이다)

 

하지만, 일단 플레이어 정보가 저장이 됐다 = 아이템 정보도 저장 가능하다.

내가 저장해야하는 것=플레이어가 구매한 아이템 리스트

지금 저장되는 요소=player 클래스

 

플레이어가 구매한 아이템 리스트 =>

 

Item class에 있는 빈 리스트. 얘가 현재 플레이어가 구매한 아이템을 저장하고 있다.

이 리스트를 플레이어 클래스>인벤토리랑 연결시키거나, 가져다 주면 될 것 같다.

그리고 아이템의 정보도 저장해야 하므로, 아이템 클래스에도 빈 생성자를 만들어주자.

 

 

player class의 필드에 만들어주고, 생성자에도 끼워줬다.

save와 load 함수도 읽기 좋게 만들도록 해준다.

 

save/load 코드

이후 확인 결과: 실패

json 파일을 열어보자 :

뭘 저장한 걸까....

아무리 봐도 아이템이 저장되어 넘어오지 않은 모양이다.

그러고보면 player class에 저장해놓고 구매/판매 메서드를 수정하지 않았다. 이게 문제인가 싶어서, 대대적으로 수정을 시작했다.

 

 

이후 다시 새로 플레이>저장 후 json 파일을 열어보자, 이번에는 제대로 아이템이 들어있는 것 같다.

다시 불러와보자.

인벤토리에 청동 활이 들어있으면 성공이다.

 

( ! ! ! )

아이템이 정상적으로 들어있다!
하지만 다음 문제가 남아있었으니

:

주인장 이게 왜 재고가 있는 것이오?

 

이럴거면 receiptItem 리스트 위치 안 옮겼지 이녀석들아!!!!

 

 

 

3. <절망>

이 글을 올리는 시간까지 해결이 안되었기 때문에, 문제를 정리하고, 오늘의 TIL은 마칩니다.

 

내가 원한 세이브-로드가 얼마나 구현되었는가?

1. 저장-불러오기가 오류코드 없이 작동된다. (O)

2. 캐릭터 정보가 정상적으로 불러와진다. (O)

3. 구매/착용한 아이템 정보가 정상적으로 불러와진다. (O)

4. 상점에서 구매한 아이템의 정보가 정상적으로 불러와진다. (X)

 

75%는 해결되어서 다행이라고 생각합니다.

지금 드는 생각: 상점 주인이 재고 채워 넣고 싶었나봐….