TextRPG개발 프로젝트

오수호·2025년 4월 16일

TIL

목록 보기
6/60

VisualStudio에서 콘솔 기반으로 동작하는 TextRPG를 만들어 보았다.
오늘 모두 개발완료한 것은 아니지만, 내일 중으로 계획한 모든 기능을 구현할 수 있을 것으로 생각한다.

가장 처음 프로젝트를 시작할 때는 막막한 기분이였다. Scene과 View가 제공되는 유니티에서와는 다르게 콘솔에서 Text기반으로 동작하는 RPG를 만들어야 하기 때문에, 어디서부터 시작해야할 지 감이 안왔기 때문이다. 그래서 울단 구현하고자 하는 내용 하나씩 하나씩 차근차근 구현해나가며, 부족한 부분을 만들고 잘못된 로직을 고쳐나가는 방식으로 구현해 나가기로 했다.

먼저, Player클래스를 만들었다. 게임을 하는데에 있어서 가장 기본이 되는 것은 플레이어이기 때문에 Player클래스를 만들게 되었고, 멤버변수로 level과 name, health을 추가하였다. 여기서, 저번 C#기초 프로그래밍에서 배운내용인 delegate를 사용해보고 싶어서 level과 health의 값이 변화할 때, delegate를 통해 callback메서드를 호출하는 방식으로 구현하여 보았다.
그리고, 플레이어의 직업을 만들어 주기 위하여 public으로 열거형 자료구조인 Job을 만들었다. Job에는 Worrior, Mage, Archor를 만들었고 Worrior에는 1을 부여하여 주었다.

    class Player
    {
        private string name;
        public string NAME
        {
            get { return name; }
            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    throw new ArgumentException("Name cannot be null or empty.");
                }
                name = value;
            }
        }

        private int level = 1;
        public int LEVEL
        {
            get { return level; }
            set
            {
                level = value;
                OnLevelChangedCallback?.Invoke(level);
            }
        }
        private Action<int>? OnLevelChangedCallback;
        public void SetLevelChangedCallback(Action<int> callback)
        {
            OnLevelChangedCallback = callback;
        }

        private int health=100;
        public int HEALTH
        {
            get { return health; }
            set
            {
                health = value;
                OnHealthChangedCallback?.Invoke(health);
            }
        }

        private Action<int>? OnHealthChangedCallback;
        public void SetHealthChangedCallback(Action<int> callback)
        {
            OnHealthChangedCallback = callback;
        }

        private Job job;
        public Job JOB
        {
            get { return job; }
            set
            {
                job = value;
            }
        }


    }
    
   
   
 public enum Job
 {
     전사 = 1,
     법사,
     궁수
 }

다음으로 GameManager 클래스를 만들어서, GameManager클래스의 메서드로 Init()을 작성하여 Player으로부터 값을 입력받아 직업과 이름을 선택할 수 있게 만들었다. 여기서 직업 선택은 SelectJob()이라는 메서드에서 처리해주고, 이름은 InputName()이라는 메서드에서 입력받도록 처리하였다. 코드의 가독성을 높이고, 유지보수를 쉽게 할 수 있도록 고려하였다.
그리고, 게임을 본격적으로 시작하면 플레이어가 선택하는 Menu에 따라서 플레이어의 활동을 결정할 수 있도록 만들었다.
이때, Menu는 enum형으로 만들어 관리하였고 플레이어의 상태를 보는 메뉴구현은 GameManager내부의 WatchState()로 작성하였다. 여기서 한 가지 드는 생각은, Player클래스에 플레이어의 상태를 출력하는 메서드를 만들고 이를 유저가 상태보기 메뉴를 골랐을 때, 호출하는 방식으로 만드는 것이 유지보수나 코드재사용 등의 방면에서 더 좋았을 것 같다.

class GameManager
{
   private string? playerInput;
   private Player player;

   public void StartGame()
   {
       Init();

   }
   private void SelectJob()
   {
       bool isJobNull = true;
       Job job;
       while (isJobNull)
       {
           Console.WriteLine("원하시는 직업을 선택해 주세요.");
           Console.WriteLine("1.전사\t2.법사\t3.궁수\n");
           playerInput = Console.ReadLine();
           Console.Write("\n");
           if (playerInput != null)
           {
               try
               {
                   job = (Job)int.Parse(playerInput);
               }
               catch (FormatException e)
               {
                   Console.WriteLine("잘못된 입력입니다. 다시 입력해 주세요.\n");
                   continue;
               }
               switch (job)
               {
                   case Job.전사:
                       player.JOB = Job.전사;
                       break;
                   case Job.법사:
                       player.JOB = Job.법사;
                       break;
                   case Job.궁수:
                       player.JOB = Job.궁수;
                       break;
                   default:
                       Console.WriteLine("잘못된 입력입니다. 다시 입력해 주세요.\n");
                       continue;
               }
               Console.Clear();
               Console.WriteLine($"{job}직업을 선택하셨습니다.\n");
               isJobNull = false;
           }
           else
           {
               Console.WriteLine("잘못된 입력입니다. 다시 입력해 주세요.\n");
               continue;
           }
       }
   }

   private void InputName()
   {
       bool isNameNull = true;
       string? name = null;
       while (isNameNull)
       {

           if (string.IsNullOrEmpty(name))
           {
               Console.WriteLine("이름을 입력해 주세요.\n");
               name = Console.ReadLine();
           }
           if (!string.IsNullOrEmpty(name))
           {
               Console.WriteLine();
               Console.WriteLine($"{name}으(로) 이름을 하시겠습니까?\n1.저장\t2.취소");
               Console.WriteLine();
               try
               {
                   playerInput = Console.ReadLine();
                   Console.WriteLine();
                   if (playerInput != null)
                   {

                       if (int.Parse(playerInput) == 2)
                       {
                           Console.WriteLine("이름을 다시 입력해 주세요.");
                           name = null;
                           continue;
                       }
                       else if (int.Parse(playerInput) == 1)
                       {
                           Console.Clear();
                           Console.WriteLine($"당신의 이름은 {name}으(로) 저장되었습니다.");
                           player.NAME = name;
                           isNameNull = false;

                       }
                       else
                       {
                           Console.WriteLine("잘못된 입력입니다. 다시 입력해 주세요.\n");
                           continue;

                       }


                   }
               }
               catch (FormatException e)
               {
                   Console.WriteLine("잘못된 입력입니다. 다시 입력해 주세요.");
                   continue;
               }

           }
           else
           {
               Console.WriteLine("잘못된 입력입니다. 다시 입력해 주세요.");
               continue;
           }
       }
   }

   private void WatchState()
   {
       while (true)
       {
           
           Console.WriteLine("상태보기");
           Console.WriteLine("캐릭터의 정보가 표시됩니다.\n");
           Console.WriteLine($"Lv. {player.LEVEL}      \r\n{player.NAME} ({player.JOB})\r\n공격력 : 10\r\n방어력 : 5\r\n체 력 : 100\r\nGold : 1500 G\r\n");
           Console.WriteLine("0.나가기\n");
           Console.Write("원하시는 행동을 입력해 주세요.>> ");
           playerInput = Console.ReadLine();
           if (!string.IsNullOrEmpty(playerInput))
           {
               if (int.Parse(playerInput) == 0)
               {
                   Console.Clear();
                   Console.WriteLine("상태보기를 종료합니다.\n");
                   return;
               }
               else
               {
                   Console.Clear();
                   Console.WriteLine("잘못된 입력입니다. 다시 입력해 주세요.\n");
                   continue;
               }
           }
           else
           {
               Console.Clear();
               Console.WriteLine("잘못된 입력입니다. 다시 입력해 주세요.\n");
               continue;
           }
       }
   }

   

   private void SelectMenu()
   {
       Menu menu;
       Console.Write("스파르타 마을에 오신 여러분 환영합니다.\r\n이곳에서 던전으로 들어가기전 활동을 할 수 있습니다.\r\n\r\n1. 상태 보기\r\n2. 인벤토리\r\n3. 상점\r\n\r\n원하시는 행동을 입력해주세요.>> ");
       playerInput = Console.ReadLine();
       if (playerInput == null)
       {
           Console.Clear();
           Console.WriteLine("잘못된 입력입니다. 다시 입력해 주세요.\n");
           return;
       }
       else
       {
           menu = (Menu)int.Parse(playerInput);
           switch (menu)
           {
               case Menu.상점:
                   Console.Clear();
                   Console.WriteLine("상점에 오신 것을 환영합니다.");
                   break;
               case Menu.인벤토리:
                   Console.Clear();
                   Console.WriteLine("인벤토리에 오신 것을 환영합니다.");
                   break;
               case Menu.상태보기:
                   Console.Clear();
                   WatchState();
                   break;
               default:
                   Console.Clear();
                   Console.WriteLine("잘못된 입력입니다. 다시 입력해 주세요.\n");
                   break;
           }   //메뉴 선택에 따라서 행동

       }




   }

   private void Init()
   {
       player = new Player();

       SelectJob();
       InputName();
       while (true)
       {
           //playerInput = null;
           SelectMenu();

       }

   }
}


   public enum Menu
   {
       상태보기 = 1,
       인벤토리,
       상점
   }

내일의 목표는 item과 inventory, 상점등을 구현하고 추가적인 구현도 완료하는 것이다.

profile
게임개발자 취준생입니다

0개의 댓글