C# 절차지향 TextRPG 만들기 04

Mr.Seo·2025년 12월 18일

C# 기초문법

목록 보기
15/15

TextRPG 전투

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 를 다시 만들어 보면서 더 자세히 만들어 보도록 하자.

  • 일단 지금 이 공부에서 중요한건 enumstruct의 구조가 어떤식으로 되어 있는지 refout을 왜 사용하고 사용하면 결과값이 어떻게 달라지는지에 대해서 생각을 해보도록 하자.

  • 그리고 몬스터와 플레이어의 생성과 초기화 방식을 생각해보고 함수를 활용해서 이 데이터들을 어떻게 처리하고 게임에서 활용하는지 곰곰히 생각해 보도록 하자.

profile
프로그래머 취준생

0개의 댓글