Unity 내일배움캠프 TIL 0818 | 코드 컨벤션 | 개인 과제 스파르타 던전 설계 및 구현

cheeseonrose·2023년 8월 18일
0

Unity 내일배움캠프

목록 보기
14/89
post-thumbnail

신나는 금요일 사실 안 신남.
다 제출한 과제를 싹 다 갈아엎어야 되는 사람의 심정을 아십니까

아ㅋㅋ 누가 일을 두 번씩 해요ㅋㅋ

안녕하세요 누 입니다.

매니저님한테 슬랙 디엠 드렸는데 답이 없으시길래 오늘 게더에서 다른 매니저님을 찾아갔다
여쭤봤는데 내 방식대로 짠 코드를 제출했다고 문제가 생기진 않을 거라고 하셨다.. 휴... 좋은 경험하셨다고..... 네..그래요..............

그래도 요구사항이 어쨌든 있는 과제니까 다시 풀어는 봐야지..힝

과제 다시 풀다가 12시가 되어서 개인 과제 발제 시간이 왔다 두둥 !
주제는 텍스트 RPG 게임을 만드는 것!!! 와!
4주차 때 내가 만들었던 게임이랑 방식이 매우 비슷해서 운 좋게도 설계할 시간이 줄었다!
그래서 바로 구현 시작하고, 중간중간 설계 부분 수정하면서 진행했당

일단 과제 얘기는 기니까 7시에 진행한 코드 컨벤션 특강 내용부터 정리~

코드 컨벤션 특강

이름 규칙(Naming Conventions)

  • camelCase : 첫 단어는 소문자로, 그 뒤의 단어는 대문자로 표시하여 구분
  • PascalCase : 단어의 첫 문자를 모두 대문자로 표시하여 구분
  • snake_case : 모두 소문자로 표시하고, "_"로 구분
  • kebab-case : 모두 소문자로 표시하고, "-"로 구분

Unity 작업시 권장하는 코딩 규칙

  • File : PascalCase
  • Namespaces, Classes, Structs : PascalCase
  • 아 하나 놓쳤다!!!! 아닌가?! 뭔ㄱ ㅏ지나갔는데 !!!
  • Non public Fields, Properties : camelCase
  • Local Variables, Parameters : camelCase



개인 과제 - 스파르타 던전 게임 만들기

설계

  • 일단 오늘 설계는 여기까지.. 추후에 변경될 가능성 매우 많음!!!
  • 몬스터 부분은 나중에 뭔가 넣을 것 같아서 일단 지우지 않고 뒀다.
  • Player랑 Item 부분은 요구사항에 맞게 프로퍼티랑 메서드 부분 약간 수정했고, 새롭게 Store 클래스를 추가했다.
  • Player와 Store의 정보를 보여주고 업데이트하는 로직은 웬만하면 Player와 Store 클래스 안에서 처리할 수 있도록 했다. 이렇게 해놔야 뭔가 나중에 로직 수정할 때 클래스 하나만 찾아보면 되니까 편할 것 같았음..ㅇㅅㅇ
    이게 맞는 방법인지는 모르겠지만!!!



구현

Main 함수 로직

  • 원래 나는 플레이어 닉네임을 받아오고 시작했는데, 여기는 그런 부분이 없길래 그냥 추가했다! 닉네임 정하고 싶으니까!!!!
  • Main
    • 메인 함수 로직은 별거 없다. 그냥 startState 값에 따라서 알맞는 함수를 호출해주는 것!
      그냥 state가 아니라 startState인 이유는 나중에 던전에 들어가서 또 상태값이 달라지기 때문에 playState와 구분해주기 위해서!
static void Main(string[] args)
{
	InitPlayerInfo();
    InitStore();
    
    while (true)
    {
    	// 1: 상태 보기, 2: 인벤토리, 3: 상점
        if (startState == 0) DisplayStartState();
        else if (startState == 1) DisplayPlayerInfo();
        else if (startState == 2) DisplayInventoryInfo();
        else DisplayStore();
    }
}

게임 시작 화면

  • InitPlayerInfo
    • 플레이어 닉네임을 받아와서 Player 객체를 만든다.
    • 플레이어의 인벤토리 초기 상태를 설정한다.
// 플레이어 닉네임을 받아서 플레이어 객체 생성
// 초기값을 설정해줌
static void InitPlayerInfo()
{
	Console.Title = "[ 스파르타 던전 ]";
    Console.WriteLine("[ 스파르타 던전 ]");
    Console.WriteLine();
    Console.Write("Player 닉네임을 입력해주세요 : ");
    string playerName = Console.ReadLine();
    player = new Player(playerName, PLAYER_HP, PLAYER_SHIELD, PLAYER_POWER, PLAYER_MONEY, new List<Item>());
    
    player.InitItemList(GetItemFromDB(0));
    player.InitItemList(GetItemFromDB(1));
    player.InitItemList(GetItemFromDB(3));
}
  • DisplayStartState
    • 콘솔 출력 지옥의 시작
    • 환영 인사를 출력한 뒤 선택할 수 있는 상태를 보여준다.
    • 선택에 따라서 startState 값을 변경해준다.
      이렇게 변경해주면 함수가 끝나고 다시 Main 함수의 while문으로 돌아가서 startState 값에 따라 알맞는 함수를 호출해주겠죵
static void DisplayStartState()
{
	Console.Clear();
    Console.WriteLine("스파르타 마을에 오신 여러분 환영합니다.");
    Console.WriteLine("이곳에서 던전으로 들어가기 전 활동을 할 수 있습니다.");
    Console.WriteLine();
    ("1").PrintWithColor(ConsoleColor.Magenta, false);
    Console.WriteLine(". 상태 보기");
    ("2").PrintWithColor(ConsoleColor.Magenta, false);
    Console.WriteLine(". 인벤토리");
    ("3").PrintWithColor(ConsoleColor.Magenta, false);
    Console.WriteLine(". 상점");
    Console.WriteLine();
    startState = GetPlayerSelect(1, 3);
}
  • GetPlayerSelect
    • 플레이어에게 선택 값을 받아올 일이 많아서 따로 구현한 함수
    • 플레이어가 start와 end 사이의 값을 입력했는지 확인하고, 올바른 값을 선택했다면 그 값을 리턴한다.
// 플레이어의 선택이 필요할 때 값이 유효한지 확인하는 함수
// 플레이어가 start부터 end 사이의 값을 선택했다면 그 값을 리턴
static int GetPlayerSelect(int start, int end)
{
	Console.WriteLine("원하시는 행동을 입력해주세요.");
    (">> ").PrintWithColor(ConsoleColor.Yellow, false);
    int select = 0;
    bool isNum = false;
    while (true)
    {
    	isNum = int.TryParse(Console.ReadLine(), out select);
        if (!isNum || (select < start || select > end))
        {
        	("잘못된 입력입니다. 다시 고르세요").PrintWithColor(ConsoleColor.Red, true);
        }
        else break;
    }
    return select;
}

상태 보기

  • DisplayPlayerInfo
    • DisplayStartState에서 상태 보기를 선택했다면 Main 함수의 while문에서 startState 값에 따라 이 함수를 실행해준다.
    • player에게 정보를 보여달라고 요청한 뒤, 선택 값을 받아와서 다시 시작 화면으로 돌아간다.
      select에는 무조건 0이 들어가게 되므로, startState를 0으로 설정
      startState가 0일 때, 다시 시작 화면을 출력하는 DisplayStartState가 실행된다.
// 시작 화면에서 상태 보기 선택시 실행
// 화면에 플레이어의 정보 표시
// 레벨, 이름, 직업, 공격력, 방어력, 체력, Gold
static void DisplayPlayerInfo()
{
	Console.Clear();
    ("상태 보기").PrintWithColor(ConsoleColor.Yellow, true);
    Console.WriteLine("캐릭터의 정보가 표시됩니다.");
    Console.WriteLine();
    
    player.DisplayPlayerInfo();
    Console.WriteLine(); Console.WriteLine();
    
    ("0").PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(". 나가기");
    Console.WriteLine();
    
    int select = GetPlayerSelect(0, 0);
    if (select == 0) startState = select;
}
  • Player.DisplayPlayerInfo
    • Player 클래스의 메서드로, 플레이어의 현재 정보를 보여준다.
    • 플레이어 레벨, 이름, 직업, 공격력, 방어력, 체력, Gold를 보여준다.
      • 착용한 공격 및 방어 아이템이 있다면 계산해서 함께 보여준다.
// 플레이어의 정보를 보여주는 함수
public void DisplayPlayerInfo()
{
	Console.Write("Lv. "); ("0" + level).PrintWithColor(ConsoleColor.Magenta, true);
    Console.WriteLine(name + " ( " + Job + " )");
    
    // 착용한 아이템 수치 계산
    int addAttack = 0, addShield = 0;
    foreach (Item item in itemList)
    {
    	if (item.IsEquipped)
        {
        	if (item.Type == 0) addShield += item.Value;
            else addAttack += item.Value;
        }
    }
    
    Console.Write("공격력 : "); (power.ToString()).PrintWithColor(ConsoleColor.Magenta, false);
    if (addAttack > 0)  // 공격 무기 착용시
    {
    	// 공격력 : 12 (+2)
        Console.Write(" ("); ("+").PrintWithColor(ConsoleColor.Yellow, false);
        (addAttack.ToString()).PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(")");
    }
    else Console.WriteLine();   // 공격력 : 12
    
    Console.Write("방어력 : "); (shield.ToString()).PrintWithColor(ConsoleColor.Magenta, false);
    if (addShield > 0)  // 방어구 착용시
    {
    	// 방어력 : 10 (+5)
        Console.Write(" ("); ("+").PrintWithColor(ConsoleColor.Yellow, false);
        (addShield.ToString()).PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(")");
    }
    else Console.WriteLine();   // 방어력 : 10
    
    Console.Write("체력 : "); (hp.ToString()).PrintWithColor(ConsoleColor.Magenta, true);
    Console.Write("Gold : "); (money.ToString()).PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(" G");
}

인벤토리

  • DisplayInventoryInfo
    • 플레이어의 인벤토리 상태를 보여준다.
    • 플레이어 정보를 보여주는 함수와 매우 비슷한 구조
    • 보유하고 있는 아이템이 없다면 없다고 출력
    • 플레이어에게 인벤토리 정보를 보여줄 것을 요청하고, 입력 값을 받아와서 입력값에 맞는 함수를 호출한다.
      • 1은 아이템 장착 관리, 2는 아이템 정렬, 0은 인벤토리 나가기
// 플레이어의 인벤토리 상태를 보여줌
static void DisplayInventoryInfo()
{
	Console.Clear();
    ("인벤토리").PrintWithColor(ConsoleColor.Yellow, true);
    Console.WriteLine("보유 중인 아이템을 관리할 수 있습니다.");
    Console.WriteLine();
    if (player.GetItemCount() == 0)
    {
    	Console.WriteLine();
        Console.WriteLine("보유하고 있는 아이템이 없습니다!");
    } else
    {
    	player.DisplayItemInventory(0);
        Console.WriteLine();
        
        ("1").PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(". 장착 관리");
        ("2").PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(". 아이템 정렬");
        ("0").PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(". 나가기");
        Console.WriteLine();
        
        int select = GetPlayerSelect(0, 2);
        if (select == 0) startState = select;
        else if (select == 1) ManagementItemInventory();
        else ArrangeItemInventory();
    }
}
  • Player.DisplayItemInventory
    • Player 클래스의 메서드로, type에 따라 플레이어의 인벤토리 상태를 보여준다.
      • type이 0이면 그냥 인벤토리 상태를, type이 1이면 아이템 장착 관리 상태일 때의 인벤토리 상태를 보여준다.
      • 장착 관리 상태일 때는 아이템에 번호를 붙여서 보여줌
    • Player 클래스의 프로퍼티인 itemList를 foreach로 순회하면서 item 정보를 출력한다.
      • item type이 0이면 방어 아이템, 1이면 공격 아이템
// 플레이어의 현재 아이템 인벤토리 상태를 보여주는 함수
// type이 0이면 인벤토리, type이 1이면 인벤토리 - 장착 관리 상태
public void DisplayItemInventory(int type)
{
	Console.WriteLine("[ 아이템 목록 ]");
    int idx = 1;
    foreach (Item item in itemList)
    {
    	// 아이템 이름
        ("-").PrintWithColor(ConsoleColor.Yellow, false);
        // 장착 관리 상태일 경우 번호 표시
        if (type == 1) (" " + idx.ToString()).PrintWithColor(ConsoleColor.Magenta, false);
        if (item.IsEquipped) Console.Write(" [E]");
        Console.Write(" " + item.Name);
        
        Extension.MakeDivider();
        
        // 아이템 효과
        if (item.Type == 0) Console.Write("방어력 "); else Console.Write("공격력 ");
        ("+").PrintWithColor(ConsoleColor.Yellow, false);
        (item.Value.ToString()).PrintWithColor(ConsoleColor.Magenta, false);
        
        Extension.MakeDivider();
        
        // 아이템 설명
        Console.WriteLine(item.Description);
        idx++;
    }
}
  • ManagementItemInventory
    • DisplayInventoryInfo에서 장착 관리를 선택했을 때 실행되는 함수다.
    • Player 객체로 장착 관리 상태의 인벤토리를 보여줄 것을 요청한다.
    • 플레이어의 선택 값을 Player 객체로 전달하여 장착 및 해제를 하도록 요청한다.
// 인벤토리 - 장착 관리 
static void ManagementItemInventory()
{
	bool isExit = false;
    while (!isExit)
    {
    	Console.Clear();
        ("인벤토리 - 장착 관리").PrintWithColor(ConsoleColor.Yellow, true);
        Console.WriteLine("보유 중인 아이템을 장착하거나 해제할 수 있습니다.");
        Console.WriteLine();
        
        player.DisplayItemInventory(1);
        Console.WriteLine();
        
        ("0").PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(". 나가기");
        Console.WriteLine();
        
        int select = GetPlayerSelect(0, player.GetItemCount());
        if (select == 0)
        {
        	isExit = true;
            DisplayInventoryInfo();
        }
        else player.EquipItem(select - 1);
    }  
}
  • Player.EquipItem
    • Player 클래스의 메서드로, 아이템을 장착하거나 해제하는 함수이다.
    • itemIdx 값을 받아서 Player 객체의 itemList의 Item 객체를 가져온다.
      그리고 그 Item 객체의 IsEquipped 값을 반전시킨다.
// 아이템 장착 함수
// itemIdx를 받아서 현재 플레이어의 아이템 리스트 중 itemIdx번째 아이템을 장착 또는 해제
public void EquipItem(int itemIdx)
{
	Item curItem = itemList[itemIdx];
    curItem.IsEquipped = !curItem.IsEquipped ;
}

여기까지가 필수 요구사항 구현이었고, 이제 추가 요구사항 구현 시작 ~


아이템 정보를 클래스 / 구조체로 활용해보기

  • 이건 설계에서부터 이미 클래스로 구현했으니 패스함

아이템 정보를 배열로 관리하기

  • 이 부분이 좀 고민이었는데 아이템 정보가 담긴 배열을 어떻게 효율적으로 관리할 수 있을까 생각해봤다.
    근데 나중에 플레이 정보 저장하는 부분에서 파일 입출력이 있을 것 같아서 일단은 Main 함수쪽에 전역 변수로 itemDB 리스트를 생성해놓고, 추후에 파일 입출력을 적용하게 되면 파일로 빼는게 좋을듯?!
    이렇게 하는게 맞는진 모르겠다 하하하!!!
  • Item Database
    • string 배열에 아이템 정보를 담아서 int 값 index와 함께 dictionary에 저장했다.
      엥 왜 이렇게 했었지
      다시 보니까 그냥 List<string[]>으로 담아도 되는거라 이거 쓰다가 수정하고 옴
// Item Database
static List<string[]> itemDB = new List<string[]> 
{ 
	new string[] { "무쇠갑옷", "0", "5", "500", "무쇠로 만들어져 튼튼한 갑옷입니다." } ,
    new string[]{ "낡은 검", "1", "2", "600", "쉽게 볼 수 있는 낡은 검입니다." },
    new string[]{ "수련자 갑옷", "0", "9", "1000", "수련에 도움을 주는 갑옷입니다." },
    new string[]{ "스파르타의 갑옷", "0", "30", "3500", "스파르타의 전사들이 사용했다는 전설의 갑옷입니다." },
    new string[]{ "청동 도끼", "1", "8", "1200", "어디선가 사용된 것 같은 도끼입니다." },
    new string[]{ "스파르타의 창", "1", "15", "2500", "스파르타의 전사들이 사용했다는 전설의 창입니다." }
};
  • GetItemFromDB
    • itemDB의 itemIdx번째 아이템 정보가 담긴 string 배열을 받아와서 Item 객체로 만들어 반환하는 함수이다.
static Item GetItemFromDB(int itemIdx)
{
	string[] itemStr = itemDB[itemIdx];
    int idx = 0;
    return new Item(
    	itemStr[idx++],
        int.Parse(itemStr[idx++]),
        int.Parse(itemStr[idx++]),
        int.Parse(itemStr[idx++]),
       	itemStr[idx++]
    );
}

콘솔 꾸미기

  • ExtensionString.PrintWithColor
    • string의 확장 메서드를 만들었다.
      콘솔에 색상을 다르게 해서 출력할 일이 많길래 어떻게 하면 효율적으로 할 수 있을까 고민 좀 해봤다.
      처음에는 그냥 함수로 만들어서 했는데, 여러 클래스에서 같은 기능이 필요하길래 더 나은 방법이 없을까 고민하다가 찾았다!
      사실 처음에 확장 메서드 쓰려다가 Console의 확장 메서드는 안 되길래 그냥 함수로 만들었던건데, 쓰면 쓸수록 너무 (귀찮아서) 비효율적인 것 같아서 그냥 string의 확장 메서드로 만들어버림
public static class ExtensionString
{
	// string 확장 함수
    // 텍스트 색상을 변경하여 출력해줌
    // (콘솔에 출력할 텍스트, 색상, WriteLine or Write)
    public static void PrintWithColor(this string text, ConsoleColor color, bool isEnter)
    {
    	Console.ForegroundColor = color;
        if (isEnter) Console.WriteLine(text); else Console.Write(text);
        Console.ResetColor();
    }
}

인벤토리 정렬하기

  • ArrangeItemInventory()
    • DisplayInventoryInfo에서 아이템 정렬을 선택했을 때 실행되는 함수다.
    • 이름, 장착, 공격력, 방어력순으로 아이템을 정렬할 수 있으며, 선택한 값은 Player 클래스로 전달하여 정렬을 요청한다.
static void ArrangeItemInventory()
{
	bool isExit = false;
    while (!isExit)
    {
    	Console.Clear();
        ("인벤토리 - 아이템 정렬").PrintWithColor(ConsoleColor.Yellow, true);
        Console.WriteLine("보유 중인 아이템을 정렬할 수 있습니다.");
        Console.WriteLine();
        
        player.DisplayItemInventory(1);
        Console.WriteLine();
        
        ("1").PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(". 이름");
        ("2").PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(". 장착순");
        ("3").PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(". 공격력");
        ("4").PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(". 방어력");
        ("0").PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(". 나가기");
        Console.WriteLine();
        
        int select = GetPlayerSelect(0, 4);
        if (select == 0)
        {
        	isExit = true;
            DisplayInventoryInfo();
        }
        else player.ArrangeItemInventory(select);
    }
}
  • Player.ArrangeItemInventory
    • Player 클래스의 메서드로, 받아온 pivot 값에 따라 Player 객체의 itemList를 정렬한다.
      • 1: 이름 정렬
      • 2: 장착 정렬
      • 3: 공격력 정렬
      • 4: 방어력 정렬
      • 5: 권정열
    • 이름이 긴 순서대로 정렬해야 되기 때문에 OrderByDescending을 사용했다.
      근데 약간 버그가 있는 것 같기도 하고 흠! 이건 나중에 다시 봐야겠다!
    • 장착순 정렬 뒤에는 이름순으로 한 번 더 정렬
    • 공격력과 방어력 정렬은 일단 type으로 정렬을 한 번 했다.
      공격력은 1, 방어력은 0
// 플레이어의 아이템 인벤토리를 정렬하는 함수
// pivot 값에 따라 이름, 장착, 공격력, 방어력 순으로 정렬됨
public void ArrangeItemInventory(int pivot)
{
	switch (pivot)
    {
    	// 이름 정렬 (긴 순서대로)
        case 1:
        	itemList = itemList.OrderByDescending(item => item.Name.Length).ToList(); 
        	break;
        // 장착순 정렬 -> 이름순 정렬
        case 2:
        	itemList = itemList.OrderByDescending(item => item.IsEquipped).ThenByDescending(item => item.Name.Length).ToList();
        	break;
        // 타입 정렬(공격은 1이므로 1부터 나오도록) -> 공격력 정렬 -> 이름순 정렬
        case 3:
        	itemList = itemList.OrderByDescending(item => item.Type == 1).ThenByDescending(item => item.Value)
        			.ThenByDescending(item => item.Name.Length).ToList();
            break;
        // 타입 정렬(방어는 0이므로 0부터 나오도록) -> 방어력 정렬 -> 이름순 정렬
        case 4:
        	itemList = itemList.OrderByDescending(item => item.Type == 0).ThenByDescending(item => item.Value)
        			.ThenByDescending(item => item.Name.Length).ToList();
        	break;
    }
}

상점

  • DisplayStore
    • 시작 화면에서 상점을 선택했을 때 호출되는 함수다.
    • Player 객체에게 현재 플레이어의 돈 정보를 표시해줄 것을 요청한 뒤, Store 객체에게 상점 정보를 보여줄 것을 요청한다.
      이때 Player 객체에게 아이템 인벤토리 정보 요청을 할 때 type 값을 넘겨줬던 것처럼, Store 객체에게도 type 값을 넘겨준다.
      type이 0이면 그냥 상점 정보를 요청하는 것이고, 1이면 아이템을 구매할 때의 상점 정보를 요청하는 것
static void DisplayStore()
{
	Console.Clear();
    ("상점").PrintWithColor(ConsoleColor.Yellow, true);
    Console.WriteLine("필요한 아이템을 얻을 수 있는 상점입니다.");
    Console.WriteLine();
    
    player.DisplayMoney();
    Console.WriteLine();
    
    store.DisplayStore(0);
    Console.WriteLine();
    
    ("1").PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(". 아이템 구매");
    ("0").PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(". 나가기");
    
    int select = GetPlayerSelect(0, 1);
    if (select == 0) startState = select;
    else if (select == 1) BuyItem();
    else ArrangeItemInventory();
}

Player.DisplayMoney는 별거 없어서 넘어감 그냥 돈 출력하는게 끝

  • Store.DisplayStore
    • itemList에는 상점에 있는 아이템의 정보를, soldState에는 각 Item.Name을 key 값으로 해서 아이템 구매 여부를 저장한다.
    • 상점에서 아이템 구매 상태일 경우 아이템 번호를 보여준다.
    • 구매한 아이템이라면 "구매 완료"를, 아니라면 아이템의 가격을 보여준다.
private List<Item> itemList;
private Dictionary<string, bool> soldState;

// 상점의 아이템 목록을 보여주는 함수
// type이 0이면 상점, type이 1이면 상점 - 아이템 구매 상태
public void DisplayStore(int type)
{
	Console.WriteLine("[ 아이템 목록 ]");
	int idx = 1;
    foreach (Item item in itemList)
    {
    	// 아이템 이름
        ("-").PrintWithColor(ConsoleColor.Yellow, false);
        // 아이템 구매 상태일 경우 번호 표시
        if (type == 1) (" " + idx.ToString()).PrintWithColor(ConsoleColor.Magenta, false);
        Console.Write(" " + item.Name);
        
        Extension.MakeDivider();
        
        // 아이템 효과
        if (item.Type == 0) Console.Write("방어력 "); else Console.Write("공격력 ");
        ("+").PrintWithColor(ConsoleColor.Yellow, false);
        (item.Value.ToString()).PrintWithColor(ConsoleColor.Magenta, false);
        
        Extension.MakeDivider();
        
        // 아이템 설명
        Console.Write(item.Description);
        
        Extension.MakeDivider();
        
        // 아이템 가격
        if (soldState.GetValueOrDefault(item.Name)) Console.WriteLine("구매 완료");
        else
        {
        	(item.Price.ToString()).PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(" G");
        }
        
        idx++;
    }
}

상점 - 아이템 구매

  • BuyItem
    • DisplayStore에서 아이템 구매를 선택했을 때 실행되는 함수이다.
    • 아이템 구매 상태일 때의 상점 정보를 보여줄 것을 Store 객체에게 요청한다.
    • 플레이어의 선택에 따라 Store 객체에게 구매할 수 있는 아이템인지를 확인한다.
      • 구매할 수 있다면 Player 객체에게 아이템을 구매할 돈이 있는지 확인한다. 있다면 구매, 없다면 돈이 부족하다는 메세지 출력
      • 구매할 수 없다면 이미 구매한 아이템이라는 메세지 출력
static void BuyItem()
{
	bool isExit = false;
    while (!isExit)
    {
    	Console.Clear();
        ("인벤토리 - 아이템 구매").PrintWithColor(ConsoleColor.Yellow, true);
        Console.WriteLine("필요한 아이템을 구매할 수 있습니다.");
        Console.WriteLine();
        
        player.DisplayMoney();
        Console.WriteLine();
        
        store.DisplayStore(1);
        Console.WriteLine();
        
        ("0").PrintWithColor(ConsoleColor.Magenta, false); Console.WriteLine(". 나가기");
        
        int select = GetPlayerSelect(0, store.GetStoreItemCount());
        if (select == 0)
        {
        	isExit = true;
            DisplayStore();
        }
        else
        {
        	if (store.IsAbleToBuy(select - 1))
            {
            	Item selectedItem = store.GetStoreItem(select - 1);
                if (player.IsAbleToBuy(selectedItem.Price))
                {
                	store.BuyItem(select - 1);
                    player.BuyItem(selectedItem);
                    ("구매를 완료했습니다.").PrintWithColor(ConsoleColor.Blue, true);
                    Thread.Sleep(1000);
                }
                else
                {
                	("Gold가 부족합니다.").PrintWithColor(ConsoleColor.Red, true);
                    Thread.Sleep(1000);
                }
            } else
           	{
            	("이미 구매한 아이템입니다.").PrintWithColor(ConsoleColor.Blue, true);
                Thread.Sleep(1000);
            }
        }
    }
}
  • Store.IsAbleToBuy, Store.BuyItem
    • Store.IsAbleToBuy : Store itemList의 itemIdx번째 아이템을 구매할 수 있는지 확인하는 함수이다.
    • Store.BuyItem : Store itemList의 itemIdx번째 아이템을 구매하는 함수로, soldState 값을 갱신한다.
// Store itemList의 itemIdx번째 아이템이 구매할 수 있는지 확인하는 함수
public bool IsAbleToBuy(int itemIdx)
{
	string key = itemList[itemIdx].Name;
    return !soldState.GetValueOrDefault(key);
}

// 플레이어가 Store itemList의 itemIdx번째 아이템을 구매할 때 호출되는 함수
// 해당 아이템의 판매 여부를 true로 바꾸고 아이템을 리턴해줌
public void BuyItem(int itemIdx)
{
	Item selectedItem = itemList[itemIdx];
    string key = selectedItem.Name;
    soldState[key] = true;
}
  • Player.IsAbleToBuy, Player.BuyItem
    • Player.IsAbleToBuy : 아이템의 가격을 매개변수로 받아서 Player 객체의 money 값과 비교하는 함수이다. 해당 아이템의 구매 가능 여부를 판단한다.
    • Player.BuyItem : 아이템을 구매하는 함수로, Item 객체를 받아서 Player의 itemList에 추가한다. 해당 아이템의 가격만큼 Player의 money 값을 갱신한다.
public bool IsAbleToBuy(int itemPrice)
{
	return itemPrice <= money;
}

public void BuyItem(Item item)
{
	itemList.Add(item);
    money -= item.Price;
}

Extension

  • 플레이어 인벤토리 정보랑 상점 아이템 정보를 표현할 때 중간에 구분자 넣는게 계속 반복돼서 따로 Extension 클래스에 함수를 만들어줬다.
    Extension.MakeDivider(); 로 사용하면 됨
    이것도 뭔가 확장 메서드로 만들고 싶은데 딱히 만들만한게 없어서 패스!!
public static class Extension
{
	public static void MakeDivider()
    {
    	Console.Write(" ");
        ("|").PrintWithColor(ConsoleColor.Yellow, false);
        Console.Write(" ");
    }
}

TODO

  • 일단 남은 추가 기능 구현
  • 코드를 어떻게 하면 깔끔하게 정리할 수 있을지 고민
  • 적용할 수 있는 디자인 패턴 찾아보기
  • 클래스, 인터페이스 및 상속 등을 어떻게 더 효율적으로 활용할 수 있을지 고민
  • 파일 입출력 기능 추가시 아이템 정보 DB를 어떻게 관리할 것인지
    파일 입출력 넣을 때 참고할 유투브
    https://www.youtube.com/watch?v=GNSD1-y6SeM



오늘은 여기까지~~~ 마참내 주말! 얏호

~끗~

0개의 댓글