🧠 오늘의 핵심 정리
- 저장/불러오기(세이브) 기능 추가 (JSON)
- 퀘스트 진행도(미니언 5마리) 전투 처치 시 카운트 연동
- 블랙잭 미니게임 추가 + 소지금 베팅 시스템 구현
- 중간에 인벤토리 구조 변경 때문에 퀘스트 보상/저장 기능이 깨져서 복구함
💾 저장 기능 && 퀘스트 && 블랙잭 기능 추가
TextRPG 저장 기능이랑 퀘스트 추가로 블랙잭 게임 기능까지 추가했습니다. 하.. 진짜 너무 힘들다… 12시간씩 눈 빠져라 모니터 쳐다보니까 안구건조증이 온다!!!!!!!!
블랙잭은 예전에 만들어둔 게 있어서 비교적 순조롭게 붙였는데, 문제는 퀘스트였습니다… 갑자기 인벤토리 중복 방지/구조 변경이 들어오면서 내가 만들던 퀘스트 보상이 안 들어가고, 원래 들어가던 아이템까지 안 들어가고… “진짜 이게 코딩인가” 싶었음.
그 와중에 내일 코딩 테스트네 하하하하하핳하핳…
🧾 Save (WIP) : GameData + GameDataManager
저장은 JSON 파일(savegame.json)로 하기로 했고, 저장할 데이터 묶음으로 GameData 클래스를 만들었습니다. (초기에는 Player + InventoryItems + AcceptedQuests를 다 담았는데, 나중에 Character 안에 AcceptedQuests가 들어가면서 구조를 정리했습니다.)
GameData.cs (저장 데이터 컨테이너)
public class GameData
{
public Character Player { get; set; }
public List<Item> InventoryItems { get; set; }
}
GameDataManager.cs (저장/로드)
public static class GameDataManager
{
private static string savePath = "savegame.json";
public static void SaveGame(Character player, Inventory inventory)
{
var data = new GameData
{
Player = player,
InventoryItems = player.Inventory.GetItems()
};
var options = new JsonSerializerOptions
{
WriteIndented = true,
IncludeFields = true
};
string json = JsonSerializer.Serialize(data, options);
File.WriteAllText(savePath, json);
Console.WriteLine("게임이 저장되었습니다.");
}
public static void LoadGame(out Character player, out Inventory inventory)
{
player = null;
inventory = null;
if (!File.Exists(savePath))
{
Console.Clear();
Console.WriteLine("저장된 파일이 없습니다.");
return;
}
string json = File.ReadAllText(savePath);
var options = new JsonSerializerOptions
{
IncludeFields = true
};
GameData data = JsonSerializer.Deserialize<GameData>(json, options);
if (data != null)
{
player = data.Player;
player.AcceptedQuests = data.Player.AcceptedQuests ?? new List<Quest>();
inventory = new Inventory(data.InventoryItems);
player.Inventory = inventory;
Console.WriteLine("게임을 불러오는 중");
}
}
}
중간에 Inventory가 어디에 붙어있느냐가 바뀌면서 저장이 한 번 깨졌는데, 최종적으로는 “플레이어가 Inventory를 가진다” 쪽으로 맞춰서 player.Inventory.GetItems() 기반으로 저장하도록 수정했습니다.
🎮 Intro.cs에 새 게임/로드 + 저장 메뉴 추가
시작하자마자 “새 게임/로드” 선택지를 만들고, 로드 성공 시에는 Lv, 이름까지 출력되게 했습니다. 그리고 로비 메뉴에 저장/블랙잭/종료까지 붙여서 기능이 점점 게임처럼(?) 커지는 중…
Console.WriteLine("1. 새로운 게임데이터 생성");
Console.WriteLine("2. 저장된 게임데이터 로드");
GameDataManager.LoadGame(out player, out inventoryItem);
if (player != null)
{
Console.Clear();
Console.WriteLine($"Lv.{player.Level} {player.Name}님의 데이터를 로드 완료하였습니다.");
}
// 로비 메뉴
Console.WriteLine(" [④ 퀘 스 트 ]");
Console.WriteLine(" [⑤ 블 랙 잭 ]");
Console.WriteLine(" [⑥ 저 장 하 기 ]");
Console.WriteLine(" [⑦ 종 료 하 기 ]");
case "6":
GameDataManager.SaveGame(player, inventoryItem);
break;
case "7":
Console.WriteLine("게임을 플레이해주셔서 감사합니다.");
Environment.Exit(0);
break;
🃏 블랙잭 미니게임 추가
블랙잭은 이전에 만들어둔 로직이 있어서 빠르게 붙일 수 있었습니다. 이번에는 TRPG에 들어온 만큼 플레이어 골드 베팅까지 연결! 승리 시 2배, 패배 시 0배로 처리했습니다.
베팅 → 소지금 차감 → 결과에 따라 지급
public void PlayerBetting(Character player)
{
// ...
bettingMoney = money;
player.AddGold(-money); // 먼저 베팅금 차감
}
if (!card.isDead)
{
player.AddGold(bettingMoney * 2);
Console.WriteLine($"\n{bettingMoney * 2} G 획득하셨습니다.");
}
else
{
Console.WriteLine($"\n{bettingMoney} G 가 날아갔습니다.");
}
카드 덱은 Card 클래스로 분리해서 플레이어/컴퓨터 덱을 따로 관리했고, A(1 또는 11) 처리도 플레이어는 입력, 컴퓨터는 21 넘으면 1 처리로 구현했습니다.
⚔️ 퀘스트 진행도(미니언 5마리) 전투 처치 연동
오늘 제일 골치 아팠던 부분… “미니언 5마리 처치” 퀘스트를 전투와 연결하려고 처치 시 AcceptedQuests를 순회해서 카운트를 올리도록 구현했습니다.
// Monster.cs
public bool IsCounted { get; set; } // 퀘스트 카운트 중복 방지
public Monster(...) { IsCounted = false; }
// PlayerBattle.cs (몬스터 처치 시점)
foreach (var acceptedQuests in PlayerRef.AcceptedQuests)
{
if (acceptedQuests.Name == "마을을 위협하는 미니언 처치"
&& acceptedQuests.Count < acceptedQuests.Total)
{
if (m.Name == "미니언" && !m.IsCounted)
{
acceptedQuests.Count++;
}
}
}
몬스터 처치 시 퀘스트 카운트가 증가하는 로직은 처치 이벤트에서 한 번만 호출되는 구조라 현재는 중복 카운트 문제가 발생하지 않았다.
다만 이후 전투 결과를 누적 계산하는 방식으로 바뀔 경우를 대비해 IsCounted 같은 보호 장치를 고려해볼 수 있겠다고 느꼈다.
🧨 오늘의 대형 이슈: 인벤토리 구조 변경으로 보상/저장 깨짐
오늘의 진짜 핵심은 이거였습니다… 어느 순간 플레이어에 Inventory가 추가되면서 기존에 넘겨받던 inventory 파라미터랑 “실제 플레이어 인벤토리”가 달라져버렸고, 그 결과로 퀘스트 보상이 안 들어가고, 저장도 인벤이 비는 문제가 생겼습니다.
퀘스트 보상 지급 위치 수정
// before
inventory.AddItem(new Item(...));
// after
player.Inventory.AddItem(new Item(quest.RewardName, quest.RewardCount, 0,
quest.RewardAttack, quest.RewardDefense));
저장도 player.Inventory 기준으로 수정 + 로드 후 재연결
// Save
InventoryItems = player.Inventory.GetItems();
// Load
inventory = new Inventory(data.InventoryItems);
player.Inventory = inventory;
그리고 저장/로드에서 직렬화 때문에 매개변수 없는 생성자도 필요해서 Character, Item에 기본 생성자도 추가했습니다.
public Character() { }
public Item() { }
📌 오늘의 회고
오늘은 기능을 많이 붙이긴 했는데, 그만큼 “한 부분 바뀌면 연쇄로 깨지는” 경험을 제대로 했습니다. 인벤토리 구조가 바뀌니까 퀘스트 보상도 깨지고, 저장도 깨지고, 결국 “진짜 데이터의 주인이 누구냐”를 다시 맞추면서 복구했습니다.
그래도 결과적으로는: 저장/로드 되고, 블랙잭 돌아가고, 미니언 퀘스트 카운트까지 전투랑 연결됐다는 점에서 오늘 작업은 의미가 컸던 것 같습니다.
근데 내일 코딩 테스트…? (갑자기 현실)
🔜 내일 할 일
- 미니언 퀘스트 카운트 중복 방지 마무리 (
m.IsCounted = true처리) - 저장/로드 시 퀘스트 UI에서 “수락 다시 뜨는 문제” 재확인
- 코딩 테스트 대비… (짧게라도)
'내일배움캠프 본캠프' 카테고리의 다른 글
| [내일배움캠프 15일차 TIL] 팀발표 하루전 (0) | 2025.10.20 |
|---|---|
| [내일배움캠프 14일차 TIL] 배치고사 + 프로젝트 막바지 작업 (0) | 2025.10.17 |
| [내일배움캠프 12일차 TIL] 퀘스트 제작 (0) | 2025.10.15 |
| [내일배움캠프 11일차 TIL] 깃허브 데스크탑 (0) | 2025.10.14 |
| [내일배움캠프 10일차 TIL] 자율 학습 (1) | 2025.10.13 |