24.01.10 TIL - [C#] Text RPG 만들기 (5) : 남은 오류 수정

JJwoo·2024년 1월 10일
post-thumbnail

무쇠 갑옷무쇠 갑옷의 상태가?


발생 문제


인벤토리 메뉴에서 아이템을 장착하면 아이템의 앞에 "[E]" 라는 텍스트가 표시되게 하는 기능을 사용 중인데

상점 메뉴에서도 장착 아이템에 대해 "[E]아이템이름" 텍스트가 출력이 되는 문제가 생겨서

오늘도 PrintItemStatDescription() 라는 아이템 출력 관련 메서드를 패줄 것이다.


해결 과정


Item 클래스의 PrintItemStatDescription 메서드에서 아이템의 장착 상태(IsEquipped)를 확인하는 로직을 수정 할 것.

[E] 표시만 뜨면 모르겠는데,
'아이템 이름'은 왜 출력되는건가 했더니
[E]를 표시하는 조건문 로직 안을 살펴보니
텍스트 정렬 메서드(PadRightForMixedTex)의 매개 변수 기능안에 Item.Name이 엮여있어서
"[E]아이템이름" 으로 출력이 되는 듯 했다.
= 그냥 둘은 한 덩어리다.

그래서
PrintItemStatDescription()의 매개 변수에 "inInventory"라는 bool 타입의 매개 변수를 추가 해주고, 이 매개 변수가 "true"일 때만 "[E]"를 출력 할 것.


1. PrintItemStatDescription()의 코드 수정

public void PrintItemStatDescription(bool withNumber = false, int idx = 0, bool showPrice = true, bool inInventory = false) 
// 1. 매개변수에 bool inInventory = false를 추가 
{
    Console.Write("- ");

    if (withNumber)
    {
        Console.ForegroundColor = ConsoleColor.DarkMagenta;
        Console.Write("{0} ", idx);
        Console.ResetColor();
    }


                                   // 2. 요 if 문 매개 변수 안에 "&& inInventory"를 추가
    if (IsEquipped && inInventory) // 둘 다 true면,(장착했다면 + inInventoy가 ture면) [E] 표시   (인벤토리에서만 보이게 할 예정) 
    {                             
        Console.Write("[");
        Console.ForegroundColor = ConsoleColor.Cyan;
        Console.Write("E");
        Console.ResetColor();
        Console.Write("]");
        Console.Write(PadRightForMixedText(Name, 9));
    }
    else
    {
        Console.Write(PadRightForMixedText(Name, 12));
    }

  //코드 생략

코드 주석 참조, bool 값을 추가해 줌.




2. InventoryMenu(), StoreMenu()의 코드 수정


이제 인벤토리 메서드에서, inInventory 파라미터(매개변수)를 true로 설정하고

상점 메뉴에서 호출할 때는 false로 설정.

=> 기본이 false니까, 상점 관련 메뉴(구매/판매 포함) 에선 입력 생략해도 됨.

하지만 팀 작업에서는 생략 안할 듯, 다른 사람들 헷갈리니까..

// Inventory() 인벤토리 메뉴 메서드
_items[i].PrintItemStatDescription(true, i + 1, false, true);     // 4번째 매개변수가 bool inInventory

// StoreMenu() 상점 메뉴 메서드
_items[i].PrintItemStatDescription(false, i + 1, true, false);


=> 이제 아이템을 장착했을 때, 상점 화면에서 보이던 "[E]"는 사라지고
   인벤토리 화면에서만 장착 했을 때 "[E]"가 보인다.

한 줄 요약 : bool 매개변수를 하나 더 추가해주고, 두 메뉴에 따라 장착 표시 텍스트를 on/off 할 수 있게 해서 해결했다.


이제 팀 과제로 만드는 부분을 시작하는데,

   // A. 팀 과제 개요
   // 캐릭터가 던전 입장 -> 전투
   // 여러 몬스터들과 상호 작용
   // 캐릭터, 몬스터는 객체나 구조체를 활용 ( 이름, 능력, 설명 등 )
   // 캐릭터와 몬스터의 데이터를 변경했을때 어떻게 유지되는가에 대한 고민

   // 2. 필수 요구 사항

   // 게임 시작 화면
   // 상태 보기
   // 전투 시작



   // 3. 선택 사항
   // 캐릭터 생성 / 직업 선택 
   // 스킬, 치명타, 회피
   // 레벨 업
   // 보상 추가
   // 콘솔 꾸미기
   // 몬스터 종류 추가
   // 회복 아이템 ( 회복량, 체력상한, 보유량 등 )
   // 스테이지 추가
   // 게임 저장하기

   // 4. 나만의 기능을 만들어 보기, 개인 개선     대부분 짬 시킬 기능..
   // 직업 별 다른 기본 스탯
   // 추가 스탯, 스피드 (회피율에 영향을 줌)
   // 직업 별 전용 무기, 방어구
   // 무기, 방어구의 내구도 감소 및 수리  ->  (대장간) 골드 소모
   // 무기, 방어구의 확률적 강화 기능 -> (대장간) 골드 소모
   // 보스 몬스터 추가, 몬스터 치명타 or 스킬, 전투 중 포션
   // 무기, 방어구 외에 악세서리 추가


   //    기본 구현 구성

   // 클래스 설정 ( 캐릭터, 몬스터, 아이템 )

   //    스타트 화면 (한 번만 표시) -> 
   // 0. 캐릭터 생성, 이름 및 직업 선택
   // 1. 시작 화면
   // 2. 상태 보기 
   // 3. 인벤토리 - 장착, 해제 등
   // 4. 상점 - 일단 pass
   // 5. 던전 입장 -  몬스터와 전투 시작 ( 추후 던전 메뉴로 활용, 난이도 등)
   // 6. 휴식
   // 7. 게임 저장 / 불러오기
   // 8. 게임 종료



   //public enum JobType // 직업 enum, 일단 원래 배운 방식대로 구현 할 거라 미사용
   //{
   //    Warrior,
   //    Mage,
   //    Theif,
   //    Programmer,
   //}
   
    public class Character // 플레이어 캐릭터 클래스
 {
     public string Name { get; } // 이름 및 직업은 생성 시에만 설정 할 거고, '게임 중'에는 바뀌지 않기 때문에 get;만 설정
     public string Job { get; }
     public int Level { get; set; }
     //public int Exp { get; set; } // 레벨업을 위한 경험치
     public int Atk { get; set; }
     public int Def { get; set; }

     //public int Speed { get; set; } // Atk, Def 처럼 레벨업에 따라 변하며, 아이템 장착 유무 및 회피 기능에 연관, 미구현
     public int Hp { get; set; }
     // public int Mp { get; set; } 마나
     public int Gold { get; set; }


     public Character(string name, string job, int level, int atk, int def, int hp, int gold)
     {
         Name = name;
         Job = job;
         Level = level;
         //Exp = exp;
         Atk = atk;
         Def = def;
         //Speed = speed; 
         Hp = hp;
         // Mp = mp;
         Gold = gold;
     }

     // 레벨 당 스탯 증가 메서드 구현 예정
     // 
 }

 public class Monster // 몬스터 클래스
 {
     public string Name { get; }
     public int Level { get; }
     public int Hp { get; set; }
     public int Atk { get; set; }

     public static int MonsterCnt = 0; // 몬스터 배열 표시에 사용, static


     public Monster(string name, int level, int hp, int atk)
     {
         Name = name;
         Level= level;
         Hp = hp;
         Atk= atk;
      }

 }

 public class Dungeon
 {
     public string Name { get; set; }
     public int Difficulty { get; set; }
     public List<Monster> Monsters { get; set; }

     public Dungeon(string name, int difficulty)
     {
         Name = name;
         Difficulty = difficulty;
         Monsters = new List<Monster>();
     }



}

     public class Item // 아이템 클래스
 {
     public string Name { get; }
     public string Desctription { get; }
     public int Type { get; }  //    0.방어구 | 1.무기  
     public int Atk { get; set; }
     public int Def { get; set; }

     // public int Hp { get; }   물약 구현 때문에 아이템에도 int hp를 해봐야하나? 일단 대기
     public int Gold { get; set; }
     public bool IsEquipped { get; set; } // 장착 여부
     public bool IsPurchased { get; set; } // 구매 여부

     public static int ItemCnt = 0; // 아이템 배열 표시에 사용, 게임 전체에 공유 됨.

     public Item(string name, string description, int type, int atk, int def, int gold, bool isEquipped = false, bool isPurchased = false)
     {
         Name = name;
         Desctription = description;
         Type = type;
         Atk = atk;
         Def = def;
         Gold = gold;
         IsEquipped = isEquipped;    // 장착 여부
         IsPurchased = isPurchased;  // 구매 여부
     }

     public void PrintItemStatDescription(bool withNumber = false, int idx = 0, bool showPrice = false ) 
         // 아이템 스탯 및 번호 출력 관련 함수
     {
       Console.WriteLine("- ");

         if (withNumber) // 아이템 번호 표시 + 컬러링
         {
             Console.ForegroundColor = ConsoleColor.DarkBlue;
             Console.Write("{0} ", idx);
             Console.ResetColor();
         }
         if (IsEquipped) // 아이템 착용 시 + 컬러링
         {
             Console.Write("[");
             Console.ForegroundColor = ConsoleColor.Cyan; //   [ 의 뒤의 색 변경
             Console.Write("E"); // cyan 컬러
             Console.ResetColor(); // 색 리셋
             Console.Write("]");
             Console.Write(PadRightForMixedText(Name, 9)); // 장착 중인 경우는 9글자 출력, 텍스트 정렬 함수 사용
         }
         // 0이 아니라면 출력할건데, + 삼항 연산자 조건에 따라 할 거야.
         if (Atk != 0) Console.Write($"Atk {(Atk >= 0 ? " + " : "")}{Atk}"); // 스탯이 0보다 크거나 같으면 "+" 를 붙이고 아니면 " "해라(공백).
         if (Def != 0) Console.Write($"Def {(Def >= 0 ? " + " : "")}{Def}");
     }

     public static string PadRightForMixedText(string str, int totalLength) // 텍스트 정렬
     {
         int currentLength = GetPrintableLength(str); // 텍스트의 실제 길이
         int padding = totalLength - currentLength; //  총길이 - 실제길이 = int padding 추가해야 할 길이
         return str.PadRight(str.Length + padding); // padding 만큼 PadRight(문자열의 오른쪽)에 공백을 추가
     }
     public static int GetPrintableLength(string str) // 아이템 텍스트 정렬을 위해 문자별 legnth 판정 정의
     {
         int length = 0;
         foreach (char c in str)
         {
             if (char.GetUnicodeCategory(c) == System.Globalization.UnicodeCategory.OtherLetter)
             {
                 length += 2; // 한글과 같은 넓은 문자는 길이를 2로 취급
             }
             else
             {
                 length += 1; // 나머지 문자는 길이를 1로 취급
             }
         }
         return length;
     }
 }


 internal class Program
 {
     static Character _player;
     static Item[] _items;
     static Monster[] _monster;
     static Monster[] _monster2;
     static Random _random = new Random(); //  랜덤 숫자를 생성하는 데 사용 (몬스터 등)

     static void Main(string[] args)
     {
         GameDataSetting();
         PrintStartLogo();
         StartMenu(); // 시작 메뉴
         //CreatePlayerMenu(); // 캐릭터 생성 메뉴, 추후 만들면 StartMenu랑 스왑 예정, 일단 구현 X
     }

     private static void GameDataSetting() // 게임 데이터 세팅
     {
         _player = new Character("정진", "백수", 1, 10, 5, 100, 3000); // 이름 직업 레벨 공격력 방어력 체력 골드

         // 몬스터, 아이템 배열 사용
         _monster = new Monster[4];
         AddMonster(new Monster("미니언", 2, 15, 5));
         AddMonster(new Monster("공허충", 3, 10, 9));
         AddMonster(new Monster("대포 미니언", 5, 25, 8));
         AddMonster(new Monster("버섯을 든 티모", 6, 20, 9)); // 추가 몬스터


         _monster2 = new Monster[4];
         AddMonster(new Monster("미니언", 2, 15, 5));
         AddMonster(new Monster("공허충", 3, 10, 9));
         AddMonster(new Monster("대포 미니언", 5, 25, 8));
         AddMonster(new Monster("버섯을 든 티모", 6, 20, 9)); // 추가 몬스터


         _items = new Item[6];
         AddItem(new Item("냄비 뚜껑", "라면을 끓일 때 쓰는 냄비에 알맞을 것 같습니다. ", 0, 0, 5, 1000)); // 맨 앞의 숫자가 0이면 방어구, 1이면 무기
         AddItem(new Item("노스페이스 패딩", "한 때 유행했으나 지금은 어머니들이 착용하는 방한복입니다. ", 0, 0, 9, 2000));
         AddItem(new Item("스파르타의 갑옷", "스파르타의 전사들이 사용했다는 전설의 갑옷입니다.", 0, 0, 15, 3500));
         AddItem(new Item("당근 칼", "잼민이들이 이 무기를 좋아합니다.", 1, 2, 0, 600));
         AddItem(new Item("나무 목검", "쉽게 볼 수 있는 낡은 검입니다.", 1, 5, 0, 1500));
         AddItem(new Item("스파르타의 창", "스파르타의 전사들이 사용했다는 전설의 창입니다.", 1, 7, 0, 3000));
     }



     private static void AddMonster(Monster monster)
     {
         if (Monster.MonsterCnt == 4)
         {
             return; // monster 클래스 객체의 Cnt 변수가 4이면 아무 것도 안 만든다.
         }
         _monster[Monster.MonsterCnt] = monster;  //  0~4까지 ++
         Monster.MonsterCnt++;
     }

     private static void AddItem(Item item)
     {
         if (Item.ItemCnt == 6)
         {
             return; // Item클래스 객체의 ItemCnt 변수가 6이면 아무 것도 안 만든다.
         }
         _items[Item.ItemCnt] = item;  // 위 조건문과 연동하여 0에서 6까지 ++
         Item.ItemCnt++;
     }

게임 데이터, 
전투 관련 코드 생략

전부 구현 할 건 아니고 대충 큰 틀을 구상해보고

필수 기능부터 구현은 해봤는데 전투 관련 코드가 너무 난잡하다.

TextRPG 제작 개인 과제를 하면서 생각보다 많은 도움이 되었는데 (코드 구조에 대해서 많이 배웠다)

다만 연산식을 하거나, 조건문을 깔끔하게 만드는 능력이 아직 부족하고, 가장 큰 문제는 진도를 많이 못 나갔다..

당장 내일부터 알고리즘 시작인데 큰일이다.

profile
개발 모코코

0개의 댓글