마지막으로 볼 건 게임의 전체 흐름을 담당하는 Main 코드와 세이브 로드 기능이다.
먼저 Main 코드.
class Program
{
//static으로 선언안할려햇는데, 세이브 로드 기능 구현하다보니.. 바꿔보셔도 됨.
//세이브 로드 저장 용 경로. 이 프로젝트의 상위 폴더.
public static string path = AppDomain.CurrentDomain.BaseDirectory;
static SceneType curSceneType = SceneType.Lobby;
static Player player = new Player();
static Stage stage = new Stage();
static Shop shop;
//메인문
static void Main(string[] args)
{
GameStart();
}
static void GameStart()
{
//게임 종료 구분 여부
bool gameexit = false;
//진행할 스테이지의 단계를 담아둘 변수
int Curstage = 0;
//게임 종료 활성화 시 탈출
while (gameexit == false)
{
//로비(시작 시)
if (curSceneType == SceneType.Lobby)
{
int input_start = Text.GetInput("1 . 새로하기\n2 . 불러오기", 1, 2);
Console.Clear();
//불러오기 시 로딩하도록 플레이어 클래스 초기화 후 로딩.
if (input_start == 2)
{
player = new Player();
Load();
}
else
{
string name = Text.GetInput("이름을 정해주세요.");
player = new Player(name);
//디버깅 코드(버그 일어나는지 안 일어나는지 볼려고 인벤에 강제로 추가함. 신경쓰지마셈)
player.inven.AddItem(ItemDataBase.ShopDataBase[0][0].DeepCopy());
player.inven.AddItem(ItemDataBase.ShopDataBase[0][1].DeepCopy());
player.inven.AddItem(new HealthPotion().DeepCopy());
player.inven.AddItem(new HealthPotion().DeepCopy());
player.inven.AddItem(new HealthPotion().DeepCopy());
}
shop = new Shop(player);
Text.TextingLine("마을로 입장하겠습니다. 조금만 기다려주세요");
Counting(3);
//씬 이동. 타입을 마을로.
curSceneType = SceneType.Home;
}
//마을로
else if (curSceneType == SceneType.Home)
{
Console.Clear();
while (true)
{
Text.TextingLine("마을에 오신 것을 환영합니다.");
Text.TextingLine("원하시는 활동을 선택해주세요.\n");
Text.TextingLine("1 . 상태 보기\n", ConsoleColor.Green, false);
Text.TextingLine("2 . 인벤토리\n", ConsoleColor.Green, false);
Text.TextingLine("3 . 상점\n", ConsoleColor.Green, false);
Text.TextingLine("4 . 던전으로\n", ConsoleColor.Green, false);
Text.TextingLine("5. 세이브\n", ConsoleColor.Green, false);
int input = Text.GetInput(null, 1, 2, 3, 4, 5);
switch (input)
{
//상태 보기
case 1:
Console.Clear();
Text.TextingLine("플레이어의 현재 스탯입니다.", ConsoleColor.Green);
Thread.Sleep(Waitingtime);
player.ShowStat();
input = Text.GetInput("마을로 돌아가시려면 0을 입력해주세요.", 0);
Console.Clear();
break;
//인벤토리
case 2:
Console.Clear();
player.inven.ShowInventory();
Console.Clear();
break;
//상점
case 3:
Console.Clear();
input = Text.GetInput("\n\n1. 구매를 원합니다.\n\n2. 판매를 원합니다.", 1, 2);
Console.Clear();
if(input == 1)
shop.ShowShop();
if (input == 2)
shop.ShowSelling();
Console.Clear();
break;
//스테이지 선택
case 4:
Console.Clear();
Text.TextingLine(" 스테이지 목록 !");
Thread.Sleep(Waitingtime);
Text.TextingLine("-------------------------------------------------------\n", ConsoleColor.Magenta, false);
for (int i = 0; i < StageDB.stageList.Count; i++)
{
Text.Texting($"스테이지 {i + 1}. 출현 몬스터 : ", ConsoleColor.Green, false);
for(int a = 0; a < StageDB.stageList[i].monsters.Count; a++)
{
Text.Texting(StageDB.stageList[i].monsters[a].monster.Name + " , ", ConsoleColor.Red, false);
}
Console.WriteLine("\n");
}
Text.TextingLine("\n-------------------------------------------------------", ConsoleColor.Magenta, false);
input = Text.GetInput("해당 스테이지 번호를 입력해주세요", Number.Make(1,StageDB.stageList.Count));
//스테이지 설정을 불러오기 위한 데이터베이스 접근
stage = StageDB.stageList[input-1];
Text.TextingLine($"스테이지 {input}으로 이동합니다.", ConsoleColor.Green);
//스테이지 단계 저장(클리어 보수를 구분하기 위함)
Curstage = input - 1;
Counting(3);
//씬타입을 모험으로
curSceneType = SceneType.Explore;
break;
//저장 기능
case 5:
Save();
Text.TextingLine("저장되었습니다!", ConsoleColor.Green);
break;
default:
break;
}
break;
}
}
//모험(스테이지)
else if (curSceneType == SceneType.Explore)
{
Console.Clear();
Random rand = new Random();
//공격 턴을 구분하기 위함
bool isPlayerturn = true;
int clear = 0;
for (int i = 0; i < stage.length; i++)
{
Monster monster = stage.MakeMonster().GetCopy();
Text.Texting("탐험 중 ", ConsoleColor.Blue, false);
for (int a = 0; a < 5; a++)
{
Text.Texting(" . ", ConsoleColor.Blue, false);
Thread.Sleep(500);
}
Console.WriteLine();
Text.TextingLine($"당신은 {monster.Name}을 만났다!" , ConsoleColor.Magenta);
Text.SaveStartPos();
Text.TextingLine("0 . 싸운다.", ConsoleColor.Green);
Text.TextingLine("1 . 도망간다.", ConsoleColor.Green);
Text.SaveEndPos();
int input = Text.GetInput(null, 0, 1);
//연출
if(input == 0)
{
Text.Texting(" 전 ", ConsoleColor.Red);
Thread.Sleep(500);
Text.Texting(" 투 ", ConsoleColor.Red);
Thread.Sleep(1000);
}
//연출22
else
{
Text.Texting(" 귀 ", ConsoleColor.Green);
Thread.Sleep(500);
Text.Texting(" 환 ", ConsoleColor.Green);
Thread.Sleep(1000);
}
Console.Clear();
//전투 시작
if (input == 0)
{
while (true)
{
//몬스터나 플레이어가 죽을 시 전투 종료
if (player.IsDead == true || monster.IsDead == true)
{
break;
}
//플레이어 턴
if (isPlayerturn == true)
{
player.AttackEnemy(monster);
isPlayerturn = !isPlayerturn;
Thread.Sleep(1000);
}
//적 턴
else if (isPlayerturn == false)
{
monster.AttackEnemy(player);
isPlayerturn = !isPlayerturn;
Thread.Sleep(1000);
}
}
//플레이어가 패배했을 시.
if (player.IsDead == true)
{
isPlayerturn = true;
Text.TextingLine("패배하였습니다.", ConsoleColor.Red);
Text.GetInput("다음 (0 입력)", 0);
}
//플레이어가 승리했을 시
else
{
isPlayerturn = true;
Text.TextingLine("승리하였습니다.", ConsoleColor.Green);
clear++;
player.Getexp(monster.Exp);
player.Gold += monster.gold;
Text.TextingLine($"{monster.gold} 골드를 흭득하셨습니다.", ConsoleColor.Yellow);
Text.TextingLine($"{player.Name} 의 남은 체력 : {player.Health}");
if (clear == stage.length)
{
Text.GetInput(" 0. 다음 ", 0);
Console.Clear();
Text.TextingLine($"{Curstage} stage 클리어!", ConsoleColor.Yellow);
Console.WriteLine("\n");
Text.TextingLine(" 보 상 ", ConsoleColor.Yellow);
Console.WriteLine("\n");
//스테이지 클리어 함수를 담아둔 배열에서 꺼내와서 player에게 적용.
StageClear.ClearMethod[Curstage](player);
}
Text.TextingLine(" 0 . 다음 ", ConsoleColor.Green);
Text.TextingLine(" 1 . 인벤토리 열기 ", ConsoleColor.Green);
input = Text.GetInput(null, 0, 1);
if (input == 1)
{
Console.Clear();
player.inven.ShowInventory();
input = Text.GetInput(" 0. 계속 진행하기 \n 1 . 마을로 돌아가기 ", 0, 1);
}
}
Console.Clear();
//마을 귀환을 택할 경우 반복문(모험) 탈출
//0이면 break를 하지 않기에 계속 반복문(모험) 진행
if (input == 1)
break;
}
//도망가기 선택 시 반복문(모험) 탈출
else
break;
//플레이어가 죽엇을 시 반복문을 탈출(while문 조건을 채운다)
if (player.IsDead == true)
{
gameexit = true;
break;
}
}
//씬 타입을 마을로
curSceneType = SceneType.Home;
}
}
//while문 탈출(게임 종료 활성화 시 = 사망) 스탯창을 띄우고 게임 종료
Console.Clear();
Console.WriteLine("게임 끝!");
player.ShowStat();
}
//대기 시간 구현 메서드
static void Counting(int num)
{
for (int i = 0; i < num; i++)
{
Console.Write(num - i + " ");
Thread.Sleep(1000);
}
}
다음은 세이브 로드이다.
어려웠따.
//세이브 기능. 상속받은 정보까지 가져가기 위해 All로 지정.
static void Save()
{
//player 클래스 저장(TypeNameHandling을 All로 설정하면 무슨 클래스를 상속받고 있는 지도 저장이 됨. 다만 문제를 일으킬 수 있으니 주의. 별다른 설정이 없으면
//무엇을 상속받고 있는 지는 저장이 안 된다. 로드해서 맞는 형태로 가져올 때 문제 생김.ex)Item형태로 불렀는데 상속 정보가 날아가 해당 클래스가 Item의 하위 클래스가 아니게 됨. 못 가져옴.
string userdata = JsonConvert.SerializeObject(player, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
});
//경로 설정 후 저장. 상위 폴더의 bin/Debug/해당 net 폴더 안에 들어가 있을 것이다.
File.WriteAllText(path + "\\UserData.json", userdata);
//원래는 inven 자체를 저장하려 했는데, 버그가 많이 발생해서 갖고있는 아이템이 저장되있는 inven의 items배열을 저장해보기로 함.
string inventorydata = JsonConvert.SerializeObject(player.inven.items, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
});
//경로 설정 후 저장. 상위 폴더의 bin/Debug/해당 net 폴더 안에 들어가 있을 것이다.
File.WriteAllText(path + "\\InvenData.json", inventorydata);
}
//로드 기능.
static void Load()
{
//해당 경로에 파일이 없을 시 인벤만 초기화하고 보냄.
if (!File.Exists(path + "\\UserData.json"))
{
player.inven.items = new List<IItem>();
return;
}
else
{
//같은 방식으로 All형태로 가져온다.
//경로 설정 후 읽어오기.
string userLData = File.ReadAllText(path + "\\UserData.json");
Player? userLoadData = JsonConvert.DeserializeObject<Player>(userLData, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
});
player = userLoadData;
//경로 설정 후 읽어오기.
string invenLData = File.ReadAllText(path + "\\InvenData.json");
List<IItem>? invenLoadData = JsonConvert.DeserializeObject<List<IItem>>(invenLData, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
});
//인벤이 없으면 새로 만들기.(버그 예방)
if (player.inven == null)
{
player.inven = new Inventory(player);
}
//인벤토리의 items배열에 저장되있던 아이템들을 추가.
foreach (IItem data in invenLoadData)
{
player.inven.AddItem(data);
}
Text.TextingLine("로드 성공.");
Thread.Sleep(Waitingtime);
Console.Clear();
}
}
세이브 시 문제를 일으키면
[JsonIgnore]
public Inventory inven;
Player 클래스의 위와 같은 형태로 Json형태로 읽는 것을 제외할 수 있다.(세이브에서 제외)
참고로 JsonConvert를 사용할려면 Newtonsoft라고 Project-> Nuget패키지 관리에서 설치해야 한다.
그리고 아래와 같이 선언
using Newtonsoft.Json;