24.01.04 TIL - [C#] Text RPG 만들기 (2) : 전면 수정 및 휴식 기능 추가

JJwoo·2024년 1월 5일
post-thumbnail

기본 기능은 구글링과 GPT 등 모든 수단을 총 동원해 전부 구현은 했지만 선택 추가 기능 (던전 입장해서 사냥, 아이템 판매, 게임 저장 등)은 아직 구현하지 못했다.

오늘 해결한 문제들을 기억나는 대로 나열하면

  1. 상점 아이템 구매 페이지에서 아이템을 구매했을 때, 골드 표시 대신 '구매 완료'라는 표시가 나오는데 이 부분이 다른 페이지를 가면 다시 사라지는 문제

    => 클래스나 전역 설정이 미숙해서 구매 완료의 기록이 남지 않았던게 원인이었다.


  1. 특정 페이지에서 0을 입력해서 나가야 하는데 0을 두 번 입력해야 했던 문제

    -> 0번 나가기 기능만 있는 페이지는 상관없지만, 두 가지 이상의 선택지가 있는 페이지에서 발생한 문제였다.
    0번 나가기 조건문과 1번 특수 기능 조건문에 'Readline()'이 각각 한 개씩 총 두 가지가 존제해서 발생했기에 조건문을 하나로 합침.

  2. 클래스와 전역, 리스트 활용 등이 미숙해서 다른 클래스로 아이템을 불러오지 못한 문제
    => 얼추 해결했는데 부족한 개념에 대해 보충 학습 필요

  3. 그 외 신나게 메서드를 만들어 놓고 정작 활용하지 못했던 것들 (아이템 장착 유무 함수 등)


1. 플레이어 클래스 관련

public static Store GameStore = new Store(); // GameStore 초기화, 상점Store 구매 완료 표시를 위해 생성, 게임 전체에서 접근 가능한 정적 객체
public class Player // 플레이어 클래스, 밑에 프로퍼티, 메서드(여긴 없음), 생성자 등의 행동을 관리
{
    //플레이어 프로퍼티(속성) 
    public int Level { get; set; }  // get,set -> 프로퍼티를 정의할때 사용되는 접근자
    public string PlayerName { get; set; }
    public string Job { get; set; }
    public int Att { get; set; }
    public int Def { get; set; }
    public int Hp { get; set; }
    public int Gold { get; set; }
    public List<Item> Inventory { get; set; }  // 플레이어가 가진 아이템 목록

    public Player(string playerName)  // 플레이어 클래스의 생성자, 새 플레이어 객체를 생성 할 때 호출됨
        // 플레이어의 이름(PlayerName)을 매개변수로 받고, 플레이어의 기본 속성을 초기화.
    {        
        PlayerName = playerName;
        Level = 1;
        Job = "백수";
        Att = 10;
        Def = 5;
        Hp = 100;
        Gold = 5000;
        Inventory = new List<Item>();
    }
                
            public void EquipItem(Item item) // 아이템 장착
            {
                if (!item.EquippedItem) // ! = 논리부정, 아이템 끼고 있지 않을 때 실행
                {
                    item.EquippedItem = true; // 장착중이면
                    Att += item.Attack;
                    Def += item.Defense;
                }
            }

            public void UnequipItem(Item item) // 아이템 해제
            {
                if (item.EquippedItem) // 아이템 끼고 있을 때 실행
                {
                    item.EquippedItem = false; // 장착중 아니면
                    Att -= item.Attack; 
                    Def -= item.Defense;
                }
            }
  • 역할 요약

게임의 주요 구성 요소인 플레이어를 정의하고, 필요한 기본 설정을 제공함.

플레이어의 기본 상태를 설정하고, 게임 중에 플레이어의 상태를 변경하거나 관리할 수 있는 기능들을 포함.

Store 클래스의 인스턴스를 GameStore라는 정적 객체로 만들어 상점을 관리

EquipItem(Item item) // 장착

UnequipItem(Item item) // 해체


장착 / 해제 매개변수에 !논리부정 유무에 주의 (해제에는 없다)

  • Item 객체를 매개변수로 받아 플레이어가 특정 아이템을 장착/해제 할 때 사용
  • if (!item.EquippedItem) 구문에서 느낌표(!)는 논리부정 연산자인데, item.EquippedItem이 false임을 확인하는 데 사용.
    뒤에 오는 불리언(Boolean) 표현식의 값을 반전시킨다. 즉, true는 false로, false는 true로 바뀜.
  • 간단히 말해서 아이템 장착 중이지 않을 때(!, 논리부정 연산자 때문에) 만 실행되며, 아이템이 장착되어 있을 때, (item.EquippedItem = true;) 공격력과 방어력을 장착 아이템 값만큼 올려줌.
  • 아이템 해제는 아이템 끼고 있을 때 실행되며, 장착 해제(false) 하면 공격력 방어력 수치 빼버림.

get: set:

프로퍼티를 정의할때 사용되는 접근자

  • get; : 해당 속성의 값을 읽을 수 있게 함. 클래스의 외부에서 이 속성을 호출할 때, get; 접근자를 통해 그 값을 얻을 수 있다.

  • set; 접근자는 해당 속성의 값을 설정할 수 있게 함. 클래스의 외부에서 이 속성에 값을 할당할 때, set; 접근자가 그 값을 받아서 내부 필드에 저장.
예시) 
public class Player
{
    public int Level { get; set; }
    public string PlayerName { get; set; }
    // 생략
}
Player player = new Player("나");

// get을 사용하여 값을 읽고
Console.WriteLine(player.Level); 

// set을 사용하여 값을 설정
player.Level = 2;
Console.WriteLine(player.Level); 

get;과 set; 접근자를 사용함으로써, 클래스의 필드에 대한 접근을 제어하고, 필드 값을 보다 안전하게 읽고 수정 할 수 있으며, 이는 객체 지향 프로그래밍에서 데이터 캡슐화와 정보 은닉의 중요한 원칙을 지키는 데 도움이 된다.


2. 아이템 클래스

        public class Item  // 아이템 클래스
        {
            // 아이템 프로퍼티
            public string ItemName { get; set; }  // 아이템 이름
            public string ToolTip { get; set; }   // 아이템 설명
            public int Attack { get; set; }   // 공격력
            public int Defense { get; set; }  // 방어력
            public int Price { get; set; }    // 템 가격
            public bool PurchaseItem { get; set; } // 구매 여부 
            public bool EquippedItem { get; set; } // 장착 여부

            public Item(string itemName, string toolTip, int attack, int defense, int price) // 아이템 클래스 생성자 -> 아이템 생성시 정보 제공용
            {
                ItemName = itemName; // 매개변수로 받은 값을 클래스의 속성에 할당하여 객체의 상태를 초기화
                ToolTip = toolTip; // 아이템 설명
                Attack = attack;
                Defense = defense;
                Price = price;
                PurchaseItem = false; //초기 기본값, 구매한 아이템 없음
                EquippedItem = false; //마찬가지로 장착 아이템 없음
            }
        }

요약

Item 클래스 생성자는 아이템 객체를 생성하고 초기화하는 데 필요한 매개변수가 있으며, 이를 통해 각 아이템의 고유한 속성들을 설정하고 게임 내에서 아이템이 어떻게 사용되고 표시될지 결정.


why 초기값 설정? -> 객체의 상태를 명확히 정의하여, 게임 내에서의 아이템 관리 및 사용을 쉽게 하기 위함.


여기서부터는 전부

public class Store

에 포함 되었다, 문제가 있다면 메인 함수가 실수로 저기에 들어가 있다는 것.. (작동은 잘 된다)


3. 상점 클래스, 메인 함수 등

        public class Store // 상점 클래스
        {
            public List<Item> Items { get; set; } // 상점 아이템 목록

            public Store()  // Store 생성자
            {
                Items = new List<Item> // Item 목록 초기화
        {
                    //아이템을 생성하고 특성 정의
                new Item(" 너덜너덜한 갑옷 ", "방어력 +3, 너무 오래 되서 다 뜯어져 있다.", 0 , 3, 1000),
                new Item(" 평범한 갑옷 ", "방어력 +6, 그럭저럭 입을만해 보인다.", 0, 6, 1500),
                new Item(" 고오급 갑옷 ", "방어력 +12, 그나마 괜찮아보이는 갑옷이다.", 0, 12, 3000),
                new Item(" 나뭇가지 ", "공격력 +2, 회초리로는 쓸만한 것 같다.", 3, 0, 500),
                new Item(" 살짝 휜 목검 ", "공격력 +6, 몇 번 휘두르면 부러질 것 같다 .", 6, 0, 1000),
                new Item(" 날카로운 죽창 ", "공격력 +11, 너도 나도 한 방에 갈 것 같은 대나무 창이다.", 11, 0, 2000)
        };


            }
            static void Main(string[] args) // 메인 함수
            {
                Console.WriteLine("맨땅에 헤딩 마을에 오신 것을 환영합니다.\n");
                Console.Write("당신의 이름은 무엇입니까? : ");
                string playerName = Console.ReadLine(); // 이름 짓기
                Console.WriteLine();
                InitializeStore(); // 아래에 설명
                Player player = new Player(playerName); // 입력받은 이름으로 플레이어 객체(인스턴스) 생성
                Stage stage = new Stage(); // Stage 객체 생성 
                stage.getSelect(player); // stage 클래스 내에 메인 화면 호출 함수 
            }

            private static void InitializeStore() // 상점에 아이템을 초기화하고 추가
            {
                GameStore.Items = new List<Item>()
                {
                new Item(" 너덜너덜한 갑옷 ", "방어력 +3, 너무 오래 되서 다 뜯어져 있다.", 0 , 3, 1000),
                new Item(" 평범한 갑옷 ", "방어력 +6, 그럭저럭 입을만해 보인다.", 0, 6, 1500),
                new Item(" 고오급 갑옷 ", "방어력 +12, 그나마 괜찮아보이는 갑옷이다.", 0, 12, 3000),
                new Item(" 나뭇가지 ", "공격력 +2, 회초리로는 쓸만한 것 같다.", 3, 0, 500),
                new Item(" 살짝 휜 목검 ", "공격력 +6, 몇 번 휘두르면 부러질 것 같다 .", 6, 0, 1000),
                new Item(" 날카로운 죽창 ", "공격력 +11, 너도 나도 한 방에 갈 것 같은 대나무 창이다.", 11, 0, 2000)
                };
            }

요약

  • 메인 함수
    사용자로부터 입력을 받고, 게임의 주요 객체들(Player, Store, Stage)을 초기화.
    사용자에게 다음 단계를 선택할 수 있는 인터페이스를 제공.
  • Store 클래스
    아이템을 구매할 수 있는 목록을 관리.
  • InitializeStore 메서드
    상점에 판매될 아이템들을 초기화하고 설정.
    static은 클래스의 인스턴스 없이도 호출될 수 있음을 의미.

store() 생성자와 상점 아이템 초기화 메서드에서 일일히 아이템 리스트를 설명하는 것을 좀 더 간단히 할 방법을 찾아야 할 것 같다.


여기서부터는 스테이지 클래스 { public class Stage } 로 묶어 두었음.

4. 스테이지 클래스

메뉴, 나가기, 상태창

                public void getSelect(Player player) // 플레이어 행동 선택
                {
                    while (true) // 선택 루프 시작
                    {
                        Console.Clear();
                        Console.WriteLine($"안녕하세요, {player.PlayerName}님!\n");
                        Console.WriteLine();
                        Console.WriteLine("1. 상태 보기\n");
                        Console.WriteLine("2. 인벤토리\n");
                        Console.WriteLine("3. 상점\n");
                        Console.WriteLine("4. 던전 입장\n");
                        Console.WriteLine("5. 휴식하기 \n");
                        Console.WriteLine("6. 게임 저장\n");
                        Console.WriteLine();
                        Console.WriteLine("원하시는 행동을 입력해주세요.\n");

                        if (int.TryParse(Console.ReadLine(), out int selectInput)) // out = selectinput 변수 선언

                        {
                            switch (selectInput)
                            {
                                case 1:
                                    PlayerInfo(player);
                                    break;
                                case 2:
                                    Inventory(player);
                                    break;
                                case 3:
                                    Store(player);
                                    break;
                                case 4:
                                    Dungeon(player);
                                    break;
                                case 5:
                                    Rest(player);
                                    break;
                                case 6:
                                    SaveGame(player);
                                    break;
                            }
                            if (selectInput >= 1 && selectInput <= 6)  // 1이상 6이하면 루프 종료
                                break;
                        }
                    }
                }
                public void BackSelect(Player player) // 각 옵션에서 0. 나가기  
                {
                    while (true) 
                    {
                        if (int.TryParse(Console.ReadLine(), out int userInput))
                        {
                            if (userInput == 0)
                            {
                                getSelect(player);
                                break;
                            }
                            else
                            {
                                Console.WriteLine("잘못된 입력입니다.  숫자만 입력하세요.");
                            }
                        }
                    }
                }

                private void PlayerInfo(Player player)  // 1. 플레이어 상태창
                {
                    Console.Clear(); // 텍스트 초기화 한 번
                    Console.WriteLine("\n[ 플레이어 스탯 ]\n");
                    Console.WriteLine($" Lv. {player.Level:D2}\n"); //level 옆에 D2 -> 1이 아닌 01로 표시 (두 자릿수)
                    Console.WriteLine($" 이름 : {player.PlayerName} ({player.Job})\n");
                    Console.WriteLine($" 공격력 : {player.Att}\n");
                    Console.WriteLine($" 방어력 : {player.Def}\n");
                    Console.WriteLine($" 체력 : {player.Hp}\n");
                    Console.WriteLine($" Gold : {player.Gold} G\n");

                    Console.WriteLine("\n[ 장착된 아이템 ]\n");
                    foreach (var item in player.Inventory) //  인벤토리에 있는 각 아이템에 대해 반복 실행
                    {
                        if (item.EquippedItem) // 아이템이 장착되어 있으면
                        {
                            string itemType = item.Attack > 0 ? "무기" : "갑옷"; // 공격력이 0보다 크면 무기, 아니면 갑옷 텍스트
                            Console.WriteLine($" {itemType}: {item.ItemName} - {item.ToolTip}"); 
                            // 위에서 판별한 아이템 타입 텍스트 : 아이템 이름 + 아이템 설명 출력
                        }
                    }

                    Console.WriteLine(" 원하시는 행동을 입력해주세요.\n");
                    Console.WriteLine(" 0. 나가기\n");
                    BackSelect(player); // 다시 메인 화면
                    

Player.@

player.Level, player.PlayerName, player.Job 등에서 player는 Player 객체를 가리키며, 객체의 속성에 접근하기 위해 사용.
예를 들어, player.Level은 해당 Player 객체의 Level 속성의 값(여기서는 1)을 불러온다.
player는 PlayerInfo 메서드에 매개변수로 전달된 Player 객체의 인스턴스를 참조하는 변수.

foreach (var item in player.Inventory):

  • 플레이어의 인벤토리를 순회하는 foreach 루프.인벤토리에 있는 각 아이템에 대해 반복 실행.

string itemType = item.Attack > 0 ? "무기" : "갑옷";:
삼항 연산자를 사용하여 아이템이 무기인지 갑옷인지 결정하고. item.Attack > 0이면(공격력 값이 있다면) 텍스트로 "무기", 반대라면 "갑옷"으로 분류.

  • 이 방식을 활용해서 무기, 갑옷 중복 착용을 방지하는 기능을 만들 수 있을지 고민

4-2) 인벤토리, 아이템 장착

               public void Inventory(Player player) // 2. 인벤토리, Player 객체가 매개변수
               {
                   Console.Clear();
                   Console.WriteLine("[ 인벤토리 ]\n보유 중인 아이템을 관리 할 수 있습니다.\n");
                   Console.WriteLine("[아이템 목록]\n");

                   if (player.Inventory.Count == 0)  // 인벤토리에 아이템이 없는 경우
                   {
                       Console.WriteLine("\n인벤토리에 아이템이 없습니다.\n");
                   }
                   else // 아이템이 있는 경우
                   {
                       for (int i = 0; i < player.Inventory.Count; i++) // 플레이어 아이템 숫자만큼 반복
                       {
                           string equippedStatus = player.Inventory[i].EquippedItem ? "[E] " : "    ";
                           Console.WriteLine($"{i + 1}. {equippedStatus}{player.Inventory[i].ItemName} - {player.Inventory[i].ToolTip}");
                       }
                   }
                   Console.WriteLine();
                   Console.WriteLine("원하시는 행동을 입력해주세요.\n");
                   Console.WriteLine(" 0. 나가기\n 1. 장착 관리\n");

                   int choice;
                   if (int.TryParse(Console.ReadLine(), out choice) //입력을 정수로 변환하여 선택 변수에 저장.
                   {
                       if (choice == 1) // 1을 선택하면 WearItem 메서드를 호출하여 아이템 장착/해제 기능을 실행
                       {
                           WearItem(player);
                       }
                       else if (choice == 0)  
                       {
                           getSelect(player); // 메인 메뉴로 돌아가기
                       }
                       else
                       {
                           Console.WriteLine("잘못된 입력입니다.");
                       }
                   }
                   else
                   {
                       Console.WriteLine("숫자를 입력해야 합니다.");
                   }
               }

               public void WearItem(Player player)  // 2-1 인벤토리 아이템 장착. Player 객체가 매개변수
               {
                   Console.Clear();
                   Console.WriteLine("[ 인벤토리 아이템 장착/해제 ]\n");

                   for (int i = 0; i < player.Inventory.Count; i++)  //인벤토리 내의 아이템을 순회하면서 장착 상태와 함께 출력
                   {
                       string equippedStatus = player.Inventory[i].EquippedItem ? "[E] " : "    ";
                       Console.WriteLine($"{i + 1}. {equippedStatus}{player.Inventory[i].ItemName} - {player.Inventory[i].ToolTip}");
                   }

                   Console.WriteLine("\n장착/해제할 아이템 번호를 입력하세요 (나가려면 0): \n");
                   string input = Console.ReadLine(); // 입력 받기, 문자열 값 판정
                   if (input == "0") // input이 문자열 "0" 이면
                   {
                       Inventory(player); // 0 입력 시 Inventory 메서드로 돌아감
                       return;
                   }

                   int itemIndex;
                   if (int.TryParse(input, out itemIndex)) 
                   {
                       itemIndex--; // 사용자 입력을 배열 인덱스에 맞추기 위해 1 감소
                       if (itemIndex >= 0 && itemIndex < player.Inventory.Count) // 유효한 아이템 인덱스인지 확인
                       {
                           Item selectedItem = player.Inventory[itemIndex]; //선택된 아이템을 저장
                           if (selectedItem.EquippedItem) //아이템이 이미 장착되어 있으면 해제하고
                           {
                               player.UnequipItem(selectedItem);
                               Console.WriteLine($"{selectedItem.ItemName} 해제되었습니다.");
                           }
                           else //  그렇지 않으면 장착.
                           {
                               player.EquipItem(selectedItem);
                               Console.WriteLine($"{selectedItem.ItemName} 장착되었습니다.");
                           }
                       }
                       else
                       {
                           Console.WriteLine("유효한 아이템 번호를 입력해주세요.");
                       }
                   }
                   else
                   {
                       Console.WriteLine("숫자를 입력해야 합니다.");
                   }


               }
               

여태까진 입력을 숫자 정수로 변환하여

int choice;
if (int.TryParse(Console.ReadLine(), out choice) 

이런 식으로 만들어 if (choice == 1) 이면 ~ 해라. 라고 조건문을 활용 했는데,
장착 아이템 메서드에서는

string input = Console.ReadLine(); // 입력 받기, 문자열 값 판정
if (input == "0") // input이 문자열 "0" 이면

그냥 입력 값 input을 string(문자열)으로 하고 input == 도 문자열로 인식 되는 " " 를 활용하여 구현하니 코드가 더 간단해진듯 하다. 이게 정수로 바꾸는 tryParse보다 나은듯 하다.
그리고 앞에서 수없이 사용했던 while 루프 보다 간단 한 듯? 그렇다면 while 루프는 언제 쓰는게 가장 효과적일지 생각해봐야..

갑자기 Return; 을 넣은 이유

if (input == "0")
{
    Inventory(player); // 0 입력 시 Inventory 메서드로 돌아감
    return;
}

라는 부분에서 넣었는데, 조건에 맞으면 Inventory 메서드가 호출 된다. 만약 return;을 넣지 않는다면 WearItem 메서드의 남은 부분이 계속 실행 될 수 있음, 즉 오류 방지용.. return문은 특정 조건을 만족 했을 때 메서드의 나머지 부분을 실행하기 않고 즉시 종료하기 위함, 그럼 다른 곳도 넣어줘야 할 듯.
요약 : 프로그램 흐름을 제어하고 불필요한 코드 실행을 방지


4-3) 상점, 아이템 구매

                public void Store(Player player) // 3. 상점
                {
                    Console.Clear();
                    Console.WriteLine("[ 상점 ]\n보유 중인 아이템을 관리 할 수 있습니다.\n");
                    Console.WriteLine("[보유 골드]");
                    Console.WriteLine($"{player.Gold} G\n");

                    Console.WriteLine("[ 아이템 목록 ]");
                    for (int i = 0; i < GameStore.Items.Count; i++) // 리스트 아이템 순회
                    {
                    string priceOrPurchased = GameStore.Items[i].PurchaseItem ? " - 구매 완료" : $"{GameStore.Items[i].Price}G";
                    Console.WriteLine($"{i + 1}. {GameStore.Items[i].ItemName} - {GameStore.Items[i].ToolTip} {priceOrPurchased}");
                    } // 각 아이템의 구매 상태를 확인하고 그에 따라 가격 또는 구매 완료를 표시

                    Console.WriteLine();
                    Console.WriteLine(" 원하시는 행동을 입력해주세요.\n");
                    Console.WriteLine(" 0. 나가기\n 1. 아이템 구매\n");

                    while (true)
                    {
                        if (int.TryParse(Console.ReadLine(), out int storeInput)) // 0,1 중에 택1
                        {
                            switch (storeInput)
                            {
                                case 0:
                                    getSelect(player); // 메뉴로 나가기
                                    break;
                                case 1:
                                    BuyItem(player); // 아이템 구매 메서드 호출
                                    break;
                                default:
                                    Console.WriteLine("잘못된 입력입니다. 유효한 번호를 입력하세요.\n");
                                    continue; // 다시 반복
                            }
                        }
                    }
                }

                public void BuyItem(Player player) // 3-1. 아이템 구매
                {
                    while (true) // 반복문
                    {
                        Console.Clear();
                        Console.WriteLine("[ 상점아이템 구매 ]\n보유하신 골드로 아이템을 구매 할 수 있습니다.\n");
                        Console.WriteLine("[보유 골드]");
                        Console.WriteLine($"{player.Gold} G\n");

                        Console.WriteLine("[ 아이템 목록 ]");
                        for (int i = 0; i < GameStore.Items.Count; i++) //상점 각 아이템에 대해 반복
                        {
                            string priceOrPurchased = GameStore.Items[i].PurchaseItem ? " - 구매 완료" : $"{GameStore.Items[i].Price}G";
                            Console.WriteLine($"{i + 1}. {GameStore.Items[i].ItemName} | {GameStore.Items[i].ToolTip} {priceOrPurchased}");
                        } // 구매 상태를 확인하고, 가격 또는 "구매 완료" 상태를 문자열로 설정 + 아이템 정보 출력

                        Console.WriteLine("\n구매하실 아이템의 번호를 입력하세요. 0은 뒤로 가기 입니다.");

                        if (int.TryParse(Console.ReadLine(), out int itemInput) && itemInput > 0 && itemInput <= GameStore.Items.Count) 
                            //입력을 정수로 변환하여 유효한 아이템 범위 내인지 확인
                        {
                            Item selectedItem = GameStore.Items[itemInput - 1];
                            // 선택한 아이템을 가져옴, 입력하는 아이템 번호와 배열 인덱스 차이(0부터 시작) 때문에 -1

                            if (selectedItem.PurchaseItem) //이미 구매한 아이템인 경우
                            {
                                Console.WriteLine("이미 구매한 아이템입니다.\n");
                            }
                            else if (player.Gold >= selectedItem.Price) // 충분한 골드를 가지고 있는 경우, 구매 처리
                            {
                                player.Gold -= selectedItem.Price; // 템값 만큼 플레이어의 골드를 감소
                                selectedItem.PurchaseItem = true; // bool item.PurchaseItem의 기본 false를 true
                                player.Inventory.Add(selectedItem); // 아이템을 플레이어 인벤토리에 추가
                                Console.WriteLine($"{selectedItem.ItemName} 구매를 완료했습니다.\n");
                            }
                            else // 위의 조건이 다 아닌 경우 = 결과적으로 골드가 없으면
                            {
                                Console.WriteLine("골드가 부족합니다.\n");
                            }
                        }
                        else if (itemInput == 0) // 0을 입력하면 while루프를 종료하고 메서드 종료
                        {
                            break; // 상점으로 돌아가기
                        }
                        else
                        {
                            Console.WriteLine("잘못된 입력입니다.");
                        }

                        Console.WriteLine("\n아무 키나 누르면 상점으로 돌아갑니다. ");
                        Console.ReadKey();
                    }

                    Store(player); // 메서드 종료 시점, 상점 메서드로 돌아감
                }

Item selectedItem = GameStore.Items[itemInput - 1];에서 -1을 하는 이유

  • 사용자가 입력하는 아이템 번호와 프로그래밍에서 사용하는 배열 인덱스 간의 차이 때문
    프로그래밍에서 배열의 인덱스는 일반적으로 0부터 시작.
  • 따라서, 사용자가 "1"을 입력했다면, 이는 실제로 배열에서 첫 번째 아이템을 가리키는 것이고, 배열의 첫 번째 아이템은 인덱스 0에 위치합니다. 이를 올바르게 매핑하기 위해서는 사용자의 입력에서 1을 빼야 함.
  • ex) 사용자가 "1"을 입력하면 itemInput - 1 은 0이 되고, 이는 배열의 첫 번째 요소를 의미.
    요약 : 프로그래밍의 배열 인덱스 체계 간의 차이를 교정하기 위함.

상점, 아이템 구매 메서드는 초기에 만든건데 그래서인지 쓸데 없이 복잡하다, 간결화가 필요..


5) 휴식하기

public void Rest(Player player) // 5. 휴식
{
    Console.Clear();
    Console.WriteLine($" 500 G 를 내면 체력을 회복할 수 있습니다. (보유 골드 : {player.Gold} G)\n");
    Console.WriteLine("1. 휴식하기 // 0. 나가기");

    string input = Console.ReadLine();

    if (input == "0")
    {
        getSelect(player); 
        return; // Rest() 메서드 종료
    }

    if (input == "1") // 휴식을 선택한 경우
    {
        if (player.Gold >= 500) // 골드가 500 이상 충분하다면 실행)
        {
            player.Gold -= 500; // -500골드
            player.Hp = 100; // 체력을 100까지 회복
            Console.WriteLine($"휴식을 완료했습니다. (보유 골드 : {player.Gold} G)");
        }
        else
        {
            Console.WriteLine("Gold가 부족합니다.");
        }
    }
    else
    {
        Console.WriteLine("잘못된 입력입니다.");
    }
    Console.WriteLine("\n아무 키나 누르면 돌아갑니다.");
    Console.ReadLine(); // 입력 대기
    getSelect(player); // 휴식 후 나가기 입력을 하면 종료되는 문제가 발생해서 만듦 + 리턴 추가
    return;
}

플레이어에게 휴식 옵션을 제공하고, 휴식을 통해 체력을 회복하는 기능을 담당. 선택에 따라 골드를 차감하고 체력을 회복시키거나, 나갈 수 있다.

먼저 완성한 조원 분이 참고하라고 알려주셔서 수월하게 만들 수 있었다. 간단하고 효과적으로 표현 하는게 코딩 실력의 척도인듯 싶었다.


중간후기

  • 코드를 대대적으로 수정 했는데 다시 볼 때 마다 이해가 힘들어서 복습하는 겸 최대한 주석을 달아서 설명을 넣었다.

  • 완벽하게 작성한 코드가 아니어서 개선하고 고치며 최종 완성 전에 최적화를 해야한다. 다시 리뷰를 해야겠다.

  • 해설을 보니 더 쉽게 구현할 수 있는 방법이 있었다. 내일 저녁 6시 전까지 수정하여 최종 제출 해야 한다.
profile
개발 모코코

0개의 댓글