TIL - 코드 리뷰하기

Amberjack·2024년 1월 16일
0

TIL

목록 보기
19/83
post-thumbnail
post-custom-banner

📖 24.01.16 코드 리뷰하기

오늘은 TextRPG의 마감일이기 때문에 팀원분들과 함께 코드 리뷰를 진행했다. 마지막으로 각자 진행한 코드를 살펴보면서 주석을 첨삭하거나, 에러 수정 및 더 나은 코드 작성 방안을 함께 고민했다.

📌 코드 리뷰 시 참고 사항

▪️ 확장성 & 재사용성 높은 코드

  1. 코드 안에 하드 코딩을 줄이고 매개 변수를 많이 이용.
  2. 기본값 반환은 재사용성을 해칠 수 있다. -> 값이 없을 때는 널을 반환하거나 에러를 반환해야 함.
  3. 불필요한 가정은 코드 재사용을 해친다.
  4. 열거형 값을 암묵적으로 처리하지 말자.
  5. 중요한 값을 nullable이면 안됨.

🛠️ MonsterManager의 GetReward() 수정

팀원분께서 GetReward()를 수정해주셨는데, GetReward()의 수정 사항을 함께 얘기해보았는데, 어제 아이템이 이상하게 출력되던 문제를 해결해주셨다.

▪️ 문제는 배열 문제!

문제는 dungeonMonster[]배열을 통해 아이템의 이름을 가져오려 했던 것에서 발생한 것이었다. 해당 배열은 몬스터 클래스를 랜덤하게 생성했기 때문에, 정렬 문제 및 몬스터 종류가 일정하지 않기 때문에 출력값이 이상하게 나오는 것이었다.

public void GetReward()
{
    Random rnd = new Random();
    int[] itemsCounter = new int[3];    // 낡은 대검, 초보자의 갑옷, 가시 갑옷 총 3개의 아이템만 떨어트린다.
    int gold = 0;

    foreach (Monster monster in dungeonMonsters)
    {
        if (rnd.Next(1, 101) <= 8) //8퍼 확률로
        {
            // 아이템 드랍 이벤트 전송
            EventManager.Instance.PostEvent(EventType.Item, Utilities.EventPair(eItemType.eGetFieldItem,monster.Item)); 

            // itemsCounter : 아이템 별 획득한 개수. 
            // itemsCounter[0] : "낡은 대검"
            // itemsCounter[1] : "초보자의 갑옷"
            // itemsCounter[2] : "가시 갑옷"
            if (monster.Level == 2)
            {
                itemsCounter[0]++; // 획득한 아이템 리스트에 추가 
            }
            else if (monster.Level == 3)
            {
                itemsCounter[1]++;
            }
            else
            {
                itemsCounter[2]++;
            }
        }
        EventManager.Instance.PostEvent(EventType.Quest, Utilities.EventPair(eQuestType.Monster, monster.Class)); //몬스터 수만큼 처치 이벤트 발생
        gold += monster.Gold; //몬스터 골드 총합
    }

    EventManager.Instance.PostEvent(EventType.Player, Utilities.EventPair(ePlayerType.Gold, gold)); //플레이어 골드 증가 이벤트
    Console.WriteLine();
    Console.WriteLine("[획득 아이템]");
    Utilities.TextColorWithNoNewLine($"{gold}", ConsoleColor.DarkRed);      // 플레이어가 얻은 골드 출력
    Console.WriteLine($" Gold");
    
	for (int i = 0; i < itemsCounter.Length; i++)
	{
		if (itemsCounter[i] > 0)
		{
    		// 몬스터가 가지고 있는 아이템 이름 - 개수 
			Console.WriteLine($"{dungeonMonsters[i].item} - {itemsCounter[i]}"); 
		}
	}
}

int[] itemsCounter;는 아이템들의 개수를 카운트하는 카운터들의 배열이다.
이 배열을 통해 전투 종료 후 몬스터들이 떨어트린 아이템의 개수를 각각 저장하기 위해 만들었다.

내가 원한 것은 itemsCounter가 0보다 클 때, 즉 아이템이 드랍되었을 때 해당 아이템의 이름을 dungeonMonster[]에서 가져오려 했었다.

그러나 itemsCounter는 아이템 종류가 정렬되어 저장되어 있는 반면,
dungeonMonster는 몬스터들이 랜덤한 종류로 랜덤한 수 만큼 생성되어 있었기 때문에 내가 원하던 대로 출력이 되지 않았던 것이다.

고민하던 찰나에 팀원분이 조언해주시길, 아이템 이름을 열거형으로 만들어 보라고 해주셨다. 눈이 번뜩 뜨이는 느낌을 받았다. ㅋㅋ

✨ 해결 방법

public enum MonsterItemType
{
    monsterItem1 = 0,
    monsterItem2,
    monsterItem3
}
...

public void GetReward()
{
    Random rnd = new Random();
    int[] itemsCounter = new int[3];    // 낡은 대검, 초보자의 갑옷, 가시 갑옷 총 3개의 아이템만 떨어트린다.
    int gold = 0;

    foreach (Monster monster in dungeonMonsters)
    {
        if (rnd.Next(1, 101) <= 8) //8퍼 확률로
        {
            // 아이템 드랍 이벤트 전송
            EventManager.Instance.PostEvent(EventType.Item, Utilities.EventPair(eItemType.eGetFieldItem,monster.Item)); 

            // itemsCounter : 아이템 별 획득한 개수. 
            // itemsCounter[0] : "낡은 대검"
            // itemsCounter[1] : "초보자의 갑옷"
            // itemsCounter[2] : "가시 갑옷"
            if (monster.Level == 2)
            {
                itemsCounter[0]++; // 획득한 아이템 리스트에 추가 
            }
            else if (monster.Level == 3)
            {
                itemsCounter[1]++;
            }
            else
            {
                itemsCounter[2]++;
            }
        }
        EventManager.Instance.PostEvent(EventType.Quest, Utilities.EventPair(eQuestType.Monster, monster.Class)); //몬스터 수만큼 처치 이벤트 발생
        gold += monster.Gold; //몬스터 골드 총합
    }

    EventManager.Instance.PostEvent(EventType.Player, Utilities.EventPair(ePlayerType.Gold, gold)); //플레이어 골드 증가 이벤트
    Console.WriteLine();
    Console.WriteLine("[획득 아이템]");
    Utilities.TextColorWithNoNewLine($"{gold}", ConsoleColor.DarkRed);      // 플레이어가 얻은 골드 출력
    Console.WriteLine($" Gold");

    for (int i = 0; i < itemsCounter.Length; i++)
    {
        if (itemsCounter[i] > 0)
        {
            Console.Write($"{GetMonsterItemName(i)} ");     // 아이템 이름 가져오기
            Utilities.TextColorWithNoNewLine("- ", ConsoleColor.DarkYellow);
            Utilities.TextColorWithNoNewLine($"{itemsCounter[i]}", ConsoleColor.DarkRed);
        }
    }
}

// 아이템 이름 가져오기
string GetMonsterItemName(int i)
{
    switch ((MonsterItemType)i)
    {
        case MonsterItemType.monsterItem1:
            return "낡은 대검";
        case MonsterItemType.monsterItem2:
            return "초보자의 갑옷";
        default:
            return "가시 갑옷";
    }
}

사실 해당 방법이 정답인지는 확실치 않지만, 내가 원하는 결과를 얻을 수 있었다!

MonsterItemType이라는 열거형을 선언해놓고, 이후 itemCounter를 비교하는 for문을 돌 때, 이름을 GetMonsterItemName()이라는 함수에서 switch문을 통해 i 값에 해당하는 아이템의 이름을 return 해주는 것으로 해결할 수 있었다.

🧌 몬스터 스킬 호출 문제

몬스터가 스킬을 사용하기 위해 스킬을 호출할 때, MP와 스킬 Cost를 비교하여 MP가 부족할 경우, 스킬을 null을 return 하도록 코드가 작성되어 있었다.
이 때, 몬스터의 공격 타입이 Skill로 지정될 경우, Skill이 null을 참조하기 때문에 에러가 발생했다.

🛠️ 해결 방안

public bool IsUseSkill => myState.Skill != null;

위의 코드를 통해 몬스터의 Skill이 현재 null인지 비교를 하여, null이 아닐 경우 true를, null일 경우 false 값을 저장하도록 했다.

if ((AttackType)monsterAttackType == AttackType.Skill)
{
    monster.SetSkill(skillManager.GetMonsterSkill(monster.Class, monster.GetMP));

    if (!monster.IsUseSkill)
    {
        monsterAttackType = AttackType.Attack;
    }
}

이 후, 몬스터가 스킬을 사용하려 할 때, if문을 통해 몬스터의 스킬이 null일 경우, 공격 타입을 Attack으로 변경하도록 수정했다.

🫠 예외 처리를 잘하자!

😭 오늘의 회고

정말 격정의 일주일이었던 것 같다. 원래 주저리 주저리 적어놓은 수준의 코드에서 갑자기 난이도가 확 뛰었다. 이런 식의 코드를 작성해야 될텐데... 당장 다시 작성하라고 하면 못할 것 같다. 주말에 시간이 된다면 TextRPG 코드를 복기해볼 생각이다. 정말 팀원분들이 고생이 많으셨고, 팀장이긴 한데 팀장 역할을 수행 못한 것 같아 정말 죄송하다... 😭

post-custom-banner

0개의 댓글