internal class Program
{
enum ClassType
{
None = 0,
Knight,
Archer,
Mage,
}
enum MonsterType
{
None = 0,
Slime,
Orc,
Skeleton
}
struct Player // 계속 능력치를 늘려줄수 없으니 구조체를 만들어서 관리를 한다.
{
public string job;
public int hp;
public int attack;
public int def;
}
struct Monster
{
public string name;
public int hp;
public int attack;
public int def;
}
static ClassType ChooseClass()
{
Console.WriteLine("이곳은 로비 입니다");
Console.WriteLine("직업을 선택하세요!");
Console.WriteLine("[1] 기사");
Console.WriteLine("[2] 궁수");
Console.WriteLine("[3] 법사");
ClassType choice = ClassType.None;
string input = Console.ReadLine();
switch (input)
{
case "1":
choice = ClassType.Knight;
break;
case "2":
choice = ClassType.Archer;
break;
case "3":
choice = ClassType.Mage;
break;
}
return choice;
} // 캐릭터 클래스 선택
static void CreatePlayer(ClassType choice, out Player player)
{
// 기사 hp : 100 attack : 10 defence : 10
// 궁수 hp : 75 attack : 12 defence : 7
// 법사 hp : 50 attack : 15 defence : 5
switch (choice)
{
case ClassType.Knight:
player.job = "바바리안";
player.hp = 100;
player.attack = 30;
player.def = 7;
break;
case ClassType.Archer:
player.job = "아마존";
player.hp = 75;
player.attack = 32;
player.def = 4;
break;
case ClassType.Mage:
player.job = "소서리스";
player.hp = 50;
player.attack = 35;
player.def = 2;
break;
default:
player.job = "일반인";
player.hp = 0;
player.attack = 0;
player.def = 0;
break;
}
} // 캐릭터 생성
static void CreateRandomMonster(out Monster monster)
{
Random rand = new Random();
int randMonster = rand.Next(1, 4);
MonsterType type = (MonsterType)rand.Next(1, 4); // 앞에 (int)형 변환을 하기 싫으면
// 아예 enum 타입을 받아서 switch 문으로 돌리면 변환을 안해도 상관없다.
switch (randMonster)
{
case (int)MonsterType.Slime:
Console.WriteLine("\n슬라임이 스폰 되었습니다!");
monster.name = "슬라임";
monster.hp = 20;
monster.attack = 12;
monster.def = 2;
break;
case (int)MonsterType.Orc:
Console.WriteLine("\n오크가 스폰 되었습니다!");
monster.name = "오크";
monster.hp = 40;
monster.attack = 14;
monster.def = 3;
break;
case (int)MonsterType.Skeleton:
Console.WriteLine("\n스켈레톤이 스폰 되었습니다!");
monster.name = "스켈레톤";
monster.hp = 30;
monster.attack = 13;
monster.def = 4;
break;
default:
monster.name = "없음";
monster.hp = 0;
monster.attack = 0;
monster.def = 0;
break;
}
}
static bool Fight(ref Player player, ref Monster monster)
{
Console.Clear();
// ref 를 붙여주지 않으면 함수내에서 계속 복사본을 가지고 계산을 해서 값을 넘기기 때문에 원하는
// 원본 값의 수정이 이루어 지지 않는다 그러니 원본 값의 변화를 원하면 ref, 원본값을 초기화해서 넘기고 싶을땐 out 을 선언한다.
while (true)
{
// 플레이어가 몬스터 공격
int playerDamage = Math.Max(1, player.attack - monster.def); // 최소 1데미지는 들어가고 플레이어의 공격력과 몬스터의 방어력을 뺀값
monster.hp -= playerDamage;
if (monster.hp <= 0)
{
Console.WriteLine("승리 했습니다.");
return true;
}
// 몬스터 반격
int monsterDamage = Math.Max(1, monster.attack - player.def);
player.hp -= monsterDamage;
if (player.hp <= 0)
{
Console.WriteLine("패배 했습니다.");
return false;
}
}
}
static void EnterField(ref Player player)
{
Console.Clear();
while (true)
{
Console.WriteLine("필드에 접속했습니다!");
Console.WriteLine($"{player.job}의 현재 체력 {player.hp}");
// 몬스터 생성
Monster monster;
CreateRandomMonster(out monster);
Console.WriteLine();
Console.WriteLine("[1] 전투 모드 돌입");
Console.WriteLine("[2] 일정 확률로 마을로 도망");
string input = Console.ReadLine();
if (input == "1")
{
bool win = Fight(ref player, ref monster);
if (!win) return;
}
else if (input == "2")
{
// 33% 확률로 마을로 도망
Random rand = new Random();
int randValue = rand.Next(0, 101);
if (randValue <= 33)
{
Console.WriteLine();
Console.WriteLine("도망에 성공 했습니다.");
Console.WriteLine("아무 키나 누르면 마을로 돌아갑니다..");
Console.ReadKey();
break;
}
else
{
Console.WriteLine("도망 실패 ㅠㅠ");
Console.WriteLine($"{monster.name}와 전투에 돌입 합니다. 아무 키나 눌러주세요");
Console.ReadKey();
bool win = Fight(ref player, ref monster);
if (!win) return;
}
}
}
}
static void EnterGame(ref Player player)
{
while (true)
{
Console.Clear();
Console.WriteLine($"{player.job}이 선택 되었습니다.");
Console.WriteLine("마을에 접속했습니다!");
Console.WriteLine("[1] 필드로 간다");
Console.WriteLine("[2] 로비로 돌아가기");
string input = Console.ReadLine();
switch (input)
{
case "1":
EnterField(ref player);
break;
case "2":
return;
}
}
}
static void Main(string[] args)
{
while (true)
{
Console.Clear();
ClassType choice = ChooseClass(); // 리턴값을 받아야함!
if (choice != ClassType.None)
{
// 캐릭터 생성
Player player;
CreatePlayer(choice, out player);
EnterGame(ref player);
}
else
Console.Clear();
}
}
}
필드에 접속하면 몬스터를 랜덤으로 생성하고 1번 전투를 하고 2번 일정 확률(33%)로 마을로 도망가는 기능을 넣어며 공부했다.
원래는 전투에서 패배하면 바로 로비로 돌아가야 하는데 더 자세한 게임 규칙은 객체지향을 공부하면서 객체지향을 활용한 TextRPG 를 다시 만들어 보면서 더 자세히 만들어 보도록 하자.
일단 지금 이 공부에서 중요한건 enum과 struct의 구조가 어떤식으로 되어 있는지 ref와 out을 왜 사용하고 사용하면 결과값이 어떻게 달라지는지에 대해서 생각을 해보도록 하자.
그리고 몬스터와 플레이어의 생성과 초기화 방식을 생각해보고 함수를 활용해서 이 데이터들을 어떻게 처리하고 게임에서 활용하는지 곰곰히 생각해 보도록 하자.