수정에 필요한 것들은 아래와 같다. 작성한 코드를 하나하나 수정하여 보자.
기존 코드
private static ItemInfo item1;
private static ItemInfo item2;
static void GameDataSetting()
{
// 캐릭터 정보 세팅
player = new Character("Chad", "전사", 1, 10, 5, 100, 1500);
// 아이템 정보 세팅
item1 = new ItemInfo("무쇠 갑옷", "무쇠로 만들어진 튼튼한 갑옷입니다.", 0, 10, 0);
item2 = new ItemInfo("낡은 검", "쉽게 볼 수 있는 낡은 검입니다.", 2, 0, 0);
}
public class ItemInfo
{
public string ItemName { get; set; }
public string ItemDescription { get; }
public int ItemAtk { get; set; }
public int ItemDef { get; set; }
public int ItemHp { get; set; }
public ItemInfo(string itemname, string itemdes, int itematk, int itemdef, int itemhp)
{
ItemName = itemname;
ItemDescription = itemdes;
ItemAtk = itematk;
ItemDef = itemdef;
ItemHp = itemhp;
}
}
기존 코드의 문제점은 아이템을 추가할 때마다 item1, item2 . . . 로 선언을 해줘야 한다는 아주 비생산적이라는 점이다. 배열을 쓰고 싶었으나 개념이해도가 부족해서인지 모조리 실패를 해서 어쩔 수 없이 수동 코드를 작성했었다.
그리고 클래스의 강력한 기능을 반쪽만 이용하고 있었다.
수정 코드
private static ItemInfo[] items; // 클래스를 가지고 와서 배열하는 방법이 있었다. . .
// 가려웠던 부분을 긁어주는 코드다
static void GameDataSetting() // 배열을 사용하여 아이템 정보를 관리
{
items = new ItemInfo[10];
AddItem(new ItemInfo("무쇠 갑옷", "무쇠로 만든 갑옷", 0, 0, 5, 0));
AddItem(new ItemInfo("낡은 검", "대장간 구석에 있던 검", 1, 2, 0, 0));
AddItem(new ItemInfo("생명의 돌", "왠지 들고 있으면 튼튼해지는 기분이 드는 돌", 2, 0, 0, 8));
}
static void AddItem(ItemInfo Item) // 배열에 아이템을 추가
{
if (ItemInfo.ItemCnt == 10)
{
return;
}
items[ItemInfo.ItemCnt] = Item;
ItemInfo.ItemCnt++;
}
public class ItemInfo
{
public string ItemName { get; set; }
public string ItemDescription { get; }
public int Type { get; } // 아이템별로 타입을 지정
public int ItemAtk { get; set; }
public int ItemDef { get; set; }
public int ItemHp { get; set; }
public static int ItemCnt = 0; // 아이템 정보를 배열화 시키기 위한 숫자 카운트
public bool IsEquiped { get; set; } // 아이템의 장착 여부를 판단하기 위한 bool
public ItemInfo(string itemname, string itemdes, int type, int itematk, int itemdef,
int itemhp, bool isEquiped = false)
{
ItemName = itemname;
ItemDescription = itemdes;
Type = type;
ItemAtk = itematk;
ItemDef = itemdef;
ItemHp = itemhp;
IsEquiped = isEquiped;
}
public void PrintItemDes(bool withNumber = false, int idx = 0)
{
Console.Write("- ");
if (withNumber) // 장비 장착 화면에서 아이템 앞에 번호 붙이기
{
Console.Write("{0} ", idx);
}
if (IsEquiped) // 아이템이 장착 여부를 판단하여 [E] 붙이고 떼기
{
Console.Write("[E]");
Console.Write(PadRightForMixedText(ItemName, 9)); // 아이템 이름 줄맞춤
}
else
{
Console.Write(PadRightForMixedText(ItemName, 12));
}
Console.Write(" | ");
if (ItemAtk != 0) // 아이템의 스탯을 출력하기 위해 0이면 출력x
{
Console.Write($"Atk {(ItemAtk >= 0 ? "+" : "")}{ItemAtk} ");
}
if (ItemDef != 0)
{
Console.Write($"Def {(ItemDef >= 0 ? "+" : "")}{ItemDef} ");
}
if (ItemHp != 0)
{
Console.Write($"Hp {(ItemHp >= 0 ? "+" : "")}{ItemHp} ");
}
Console.Write(" | ");
Console.WriteLine(ItemDescription);
}
// 아이템 이름의 줄맞춤을 위한 메서드
public static int GetPrintableLength(string str)
{
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;
}
public static string PadRightForMixedText(string str, int totalLength)
{
int currentLength = GetPrintableLength(str);
int padding = totalLength - currentLength;
return str.PadRight(str.Length + padding);
}
}
아이템에 의해 변하는 변수들의 정보를 클래스 내부에 넣어놓고 적절하게 호출하여 사용하는 것이 편의성도 생산성도 좋다고 느꼈다.
기존 코드
static void DisplayMyInfo()
{
Console.Clear();
Console.WriteLine("상태보기");
Console.WriteLine("캐릭터의 정보를 표시합니다.");
Console.WriteLine();
Console.WriteLine($"Lv.{player.Level}");
Console.WriteLine($"{player.Name}({player.Job})");
Console.WriteLine($"공격력 : {player.Atk}");
Console.WriteLine($"방어력 : {player.Def}");
Console.WriteLine($"체력 : {player.Hp}");
Console.WriteLine($"Gold : {player.Gold} G");
Console.WriteLine();
Console.WriteLine("0. 나가기");
if (item1.ItemName == "[E] 무쇠 갑옷" && item2.ItemName != "[E] 낡은 검")
{
Console.Clear();
Console.WriteLine("상태보기");
Console.WriteLine("캐릭터의 정보를 표시합니다.");
Console.WriteLine();
Console.WriteLine($"Lv.{player.Level}");
Console.WriteLine($"{player.Name}({player.Job})");
Console.WriteLine($"공격력 : {player.Atk}");
Console.WriteLine($"방어력 : {player.Def} +({item1.ItemDef + item2.ItemDef})");
Console.WriteLine($"체력 : {player.Hp}");
Console.WriteLine($"Gold : {player.Gold} G");
Console.WriteLine();
Console.WriteLine("0. 나가기");
}
else if (item2.ItemName == "[E] 낡은 검" && item1.ItemName != "[E] 무쇠 갑옷")
{
Console.Clear();
Console.WriteLine("상태보기");
Console.WriteLine("캐릭터의 정보를 표시합니다.");
Console.WriteLine();
Console.WriteLine($"Lv.{player.Level}");
Console.WriteLine($"{player.Name}({player.Job})");
Console.WriteLine($"공격력 : {player.Atk} +({item1.ItemAtk + item2.ItemAtk})");
Console.WriteLine($"방어력 : {player.Def}");
Console.WriteLine($"체력 : {player.Hp}");
Console.WriteLine($"Gold : {player.Gold} G");
Console.WriteLine();
Console.WriteLine("0. 나가기");
}
else if (item1.ItemName == "[E] 무쇠 갑옷" && item2.ItemName == "[E] 낡은 검")
{
Console.Clear();
Console.WriteLine("상태보기");
Console.WriteLine("캐릭터의 정보를 표시합니다.");
Console.WriteLine();
Console.WriteLine($"Lv.{player.Level}");
Console.WriteLine($"{player.Name}({player.Job})");
Console.WriteLine($"공격력 : {player.Atk} +({item1.ItemAtk + item2.ItemAtk})");
Console.WriteLine($"방어력 : {player.Def} +({item1.ItemDef + item2.ItemDef})");
Console.WriteLine($"체력 : {player.Hp}");
Console.WriteLine($"Gold : {player.Gold} G");
Console.WriteLine();
Console.WriteLine("0. 나가기");
}
int input = CheckValidInput(0, 0);
switch (input)
{
case 0:
DisplayGameIntro();
break;
}
}
지금 봐도 아주 헛웃음이 나오는 if문의 남발이다. . . 당장 고쳐버리자 !
수정 코드
static void DisplayMyInfo()
{
Console.Clear();
Console.WriteLine("상태보기");
Console.WriteLine("캐릭터의 정보를 표시합니다.");
Console.WriteLine();
Console.WriteLine("Lv. " + player.Level.ToString("00")); // 레벨을 두 자리수로 표현하기 위해
Console.WriteLine($"{player.Name}({player.Job})");
// 캐릭터의 상태에 어떻게 장비의 정보를 전달할 수 있는 삼항연산자
int bonusAtk = getSumBonusAtk();
Console.Write("공격력 : " + (player.Atk + bonusAtk).ToString());
Console.WriteLine(bonusAtk > 0 ? string.Format(" (+{0})", bonusAtk) : "");
int bonusDef = getSumBonusDef();
Console.Write("방어력 : " + (player.Def + bonusDef).ToString());
Console.WriteLine(bonusDef > 0 ? string.Format(" (+{0})", bonusDef) : "");
int bonusHp = getSumBonusHp();
Console.Write("Hp : " + (player.Hp + bonusHp).ToString());
Console.WriteLine(bonusHp > 0 ? string.Format(" (+{0})", bonusHp) : "");
Console.WriteLine($"Gold : {player.Gold} G");
Console.WriteLine();
Console.WriteLine("0. 나가기");
switch (input)
{
case 0:
DisplayGameIntro();
break;
}
}
private static int getSumBonusAtk()
{
int sum = 0;
for (int i = 0; i < ItemInfo.ItemCnt; i++)
{
if (items[i].IsEquiped)
{
sum += items[i].ItemAtk;
}
}
return sum;
}
private static int getSumBonusDef()
{
int sum = 0;
for (int i = 0; i < ItemInfo.ItemCnt; i++)
{
if (items[i].IsEquiped)
{
sum += items[i].ItemDef;
}
}
return sum;
}
private static int getSumBonusHp()
{
int sum = 0;
for (int i = 0; i < ItemInfo.ItemCnt; i++)
{
if (items[i].IsEquiped)
{
sum += items[i].ItemHp;
}
}
return sum;
}
크게 달라진 점은 메서드와 삼항연산자를 활용했다는 점이다. 처음에 코드를 작성할 땐 메서드와 bool문을 활용하면 어떻게 될 것 같은데 하면서 다양하게 시도했지만 모조리 실패를 했고, , , 이렇게 메서드와 삼항연산자를 활용하여 해결하니 속이 다 후련하다.
기존 코드
static void DisplayInventory()
{
Console.Clear();
Console.WriteLine("인벤토리");
Console.WriteLine("보유 중인 아이템을 관리할 수 있습니다.");
Console.WriteLine();
Console.WriteLine("[아이템 목록]");
Console.WriteLine($"- {item1.ItemName} " + $" | 방어력 +{item1.ItemDef} | {item1.ItemDescription}");
Console.WriteLine($"- {item2.ItemName} " + $" | 공격력 +{item2.ItemAtk} | {item2.ItemDescription}");
Console.WriteLine();
Console.WriteLine("1. 장착 관리");
Console.WriteLine("0. 나가기");
Console.WriteLine();
Console.WriteLine("원하시는 행동을 입력해주세요");
int input = CheckValidInput(0, 1);
switch (input)
{
case 0:
DisplayGameIntro();
break;
case 1:
EquipItemManagement();
break;
}
}
수정 코드
static void DisplayInventory()
{
Console.Clear();
Console.WriteLine("인벤토리");
Console.WriteLine("보유 중인 아이템을 관리할 수 있습니다.");
Console.WriteLine();
Console.WriteLine("[아이템 목록]");
//Console.WriteLine($"- {item1.ItemName} " + $" | 방어력 +{item1.ItemDef} | {item1.ItemDescription}");
//Console.WriteLine($"- {item2.ItemName} " + $" | 공격력 +{item2.ItemAtk} | {item2.ItemDescription}");
for (int i = 0; i < ItemInfo.ItemCnt; i++) // 아이템 목록을 반복문을 이용해서 자동으로 !
{
items[i].PrintItemDes();
}
Console.WriteLine();
Console.WriteLine("1. 장착 관리");
Console.WriteLine("0. 나가기");
Console.WriteLine();
Console.WriteLine("원하시는 행동을 입력해주세요");
int input = CheckValidInput(0, 1);
switch (input)
{
case 0:
DisplayGameIntro();
break;
case 1:
EquipItemManagement();
break;
}
}
기존 코드
static void EquipItemManagement()
{
Console.Clear();
Console.WriteLine("인벤토리 - 장착 관리");
Console.WriteLine("아이템을 장착하거나 해제합니다");
Console.WriteLine();
Console.WriteLine("[아이템 목록]");
Console.WriteLine($"- 1 {item1.ItemName} " + $" | 방어력 +{item1.ItemDef} | {item1.ItemDescription}");
Console.WriteLine($"- 2 {item2.ItemName} " + $" | 공격력 +{item2.ItemAtk} | {item2.ItemDescription}");
Console.WriteLine();
Console.WriteLine("0. 나가기");
Console.WriteLine();
Console.WriteLine("장착할 아이템 번호를 입력해주세요.");
Console.WriteLine("이미 장착하고 있을 경우 해제합니다.");
int input = CheckValidInput(0, 2);
switch (input)
{
case 0:
DisplayInventory();
break;
case 1:
// 1번 아이템 선택하면 캐릭터 인포에 능력치를 플러스해주고 아이템 이름 앞에 [E]를 붙였다가 떼기
if (item1.ItemName == "무쇠 갑옷")
{
item1.ItemName = "[E] 무쇠 갑옷";
player.Atk += item1.ItemAtk;
player.Def += item1.ItemDef;
player.Hp += item1.ItemHp;
}
else
{
item1.ItemName = "무쇠 갑옷";
player.Atk -= item1.ItemAtk;
player.Def -= item1.ItemDef;
player.Hp -= item1.ItemHp;
}
EquipItemManagement();
break;
case 2:
if (item2.ItemName == "낡은 검")
{
item2.ItemName = "[E] 낡은 검";
player.Atk += item2.ItemAtk;
player.Def += item2.ItemDef;
player.Hp += item2.ItemHp;
}
else
{
item2.ItemName = "낡은 검";
player.Atk -= item2.ItemAtk;
player.Def -= item2.ItemDef;
player.Hp -= item2.ItemHp;
}
EquipItemManagement();
break;
}
}
수정 코드
static void EquipItemManagement()
{
Console.Clear();
Console.WriteLine("인벤토리 - 장착 관리");
Console.WriteLine("아이템을 장착하거나 해제합니다");
Console.WriteLine();
Console.WriteLine("[아이템 목록]");
for (int i = 0; i < ItemInfo.ItemCnt; i++)
{
items[i].PrintItemDes(true, i + 1);
}
Console.WriteLine();
Console.WriteLine("0. 나가기");
Console.WriteLine();
Console.WriteLine("장착할 아이템 번호를 입력해주세요.");
Console.WriteLine("이미 장착하고 있을 경우 해제합니다.");
int input = CheckValidInput(0, ItemInfo.ItemCnt);
switch (input)
{
case 0:
DisplayInventory();
break;
default:
ToggleEquipStatus(input - 1); // items[]가 배열이라 0부터 시작하기 때문
EquipItemManagement();
break;
}
}
// case로 입력값을 받아서 [E]를 탈부착 시켜주는 코드
// 아이템 클래스의 bool 문을 호출하여 사용한다.
static void ToggleEquipStatus(int idx)
{
items[idx].IsEquiped = !items[idx].IsEquiped;
}
if문을 정말 알차게도 썼다. . . [E]의 탈부착을 bool을 이용하고 싶었는데 실패했었다. 해설 코드를 보면서 직접 사용을 해보니 머리가 트이는 기분이다.
GitHub URL: https://github.com/ssungyeee/Personal-Assignment.git
우선 계속 혼자 시도했다가 실패했던 기능들을 시원하게 구현할 수 있어서 너무 속이 후련하다. 기본적인 기능들의 개념 이해도가 얼마나 부족한지 깨달을 수 있는 시간이었고, 코드 작성의 흐름을 수박겉핥기 마냥 배울 수 있는 과제였다.