팀스파르타 코딩

스파르타 던전 프로젝트 기능 설명 및 트러블 슈팅

creator2041 2025. 4. 16. 11:16

이 문서는 게임 개발을 처음 시작하는 입장에서 마주친 문제들과, 그것을 어떻게 해결했는지를 아주 쉽게 풀어 쓴 기록입니다. 각 문제는 실제로 개발 도중 겪었던 고비들이며, 그걸 극복하면서 어떤 걸 배웠는지도 자세히 정리해두었어요.


1. 클래스 설계와 의존성 관리의 어려움

🔧 문제 상황

처음에 Player, Inventory, Shop, Game 클래스 사이의 관계를 어떻게 설정할지 몰라서 진짜 머리가 아팠어요. 예를 들어, 인벤토리는 플레이어 속성일까? 아니면 별도로 관리하는 게 좋을까? 이런 고민이 많았습니다.

🧪 시도한 해결책

Player 안에 Inventory를 넣고 쓰려고 했는데, Shop에서 인벤토리에 접근하려면 Player 전체를 들고 다녀야 했어요. 너무 복잡하고 비효율적이었어요.

✅ 최종 해결책

Game 클래스를 중심으로 두고, Player, Inventory, Shop 등은 전부 독립 객체로 만들었어요. 그리고 각 씬(Scene)은 필요한 객체만 전달받아서 쓰게 했습니다.

🎓 배운 점

  • 클래스끼리 너무 얽히지 않게 만드는 게 진짜 중요하다는 걸 느꼈어요.
  • "높은 응집도, 낮은 결합도"가 왜 강조되는지도 체감했어요.
  • 이걸 하면서 "의존성 주입"이라는 개념을 살짝 이해하게 됐습니다.

2. 참조 타입과 값 타입 이해의 어려움

🔧 문제 상황

아이템을 복사하지 않고 그대로 Inventory에 넣었더니, 하나를 바꾸면 다른 것도 같이 바뀌더라고요! 알고 보니 C#에서 클래스는 "참조 타입"이더라고요.

🧪 시도한 해결책

그냥 Add()로 넣으니 얕은 복사라서 원본이랑 연결된 상태였어요.

✅ 최종 해결책

아이템 구매할 때 new Item(...)으로 새 객체를 만들어서 넣어주었어요.

// 깊은 복사를 위해 새로운 인스턴스를 생성
Item boughtItem = new Item(
    item.Name,
    item.Description,
    item.Price,
    item.Type,
    item.AttackBonus,
    item.DefenseBonus,
    item.HealthBonus
);

🎓 배운 점

  • 참조 타입은 같은 주소를 가리키기 때문에 조심해야 해요.
  • 얕은 복사 vs 깊은 복사의 차이를 몸으로 배웠습니다.

3. 아이템 장착/해제 시스템 구현의 복잡성

🔧 문제 상황

아이템을 장착하면 능력치가 올라가고, 해제하면 다시 내려가야 하는데 이걸 어디서 처리할지가 복잡했어요.

🧪 시도한 해결책

처음엔 Item이 Player를 직접 참조하게 했는데, 클래스 간 관계가 너무 얽히더라고요.

✅ 최종 해결책

Inventory 클래스 안에 ToggleEquip() 메서드를 만들고, 여기에 능력치 증감 로직까지 다 넣었어요.

public void ToggleEquip(Item item, Player player)
{
    if (!items.Contains(item))
    {
        Console.WriteLine("해당 아이템이 인벤토리에 없습니다.");
        return;
    }

    item.ToggleEquip();

    if (player != null)
    {
        int attackMod = item.IsEquipped ? item.AttackBonus : -item.AttackBonus;
        int defenseMod = item.IsEquipped ? item.DefenseBonus : -item.DefenseBonus;

        player.UpdateStats(attackMod, defenseMod);

        if (item.IsEquipped)
            Console.WriteLine($"{item.Name}을(를) 장착했습니다.");
        else
            Console.WriteLine($"{item.Name}을(를) 해제했습니다.");
    }
}

🎓 배운 점

  • 클래스는 각자의 역할만 하게 하는 게 유지보수에 좋다!
  • 복잡한 상태 관리는 중복되지 않게 한 곳에서 처리해야 해요.

4. 콘솔 UI 구현의 제한사항 극복

🔧 문제 상황

콘솔 환경에서는 화려한 그래픽을 쓸 수가 없어서, 현재 상태나 아이템 장착 여부를 직관적으로 보여주기가 어려웠어요. 특히 텍스트로만 보여주면 어떤 아이템이 장착된 건지, 어떤 효과가 있는지 헷갈리기 쉬웠습니다.

🧪 시도한 해결책

처음엔 단순히 아이템 이름, 설명, 가격만 출력했는데, 게임을 플레이하는 입장에서 너무 불편했어요.

✅ 최종 해결책

  • 장착된 아이템 앞에 [E] 표시를 붙였어요.
  • 각 아이템을 보기 좋게 출력하도록 레이아웃을 정돈했어요.
  • 구분선을 넣고, 메뉴마다 일관성 있는 UI 형식을 사용했어요.
public void DisplayInfo()
{
    string displayName = IsEquipped ? $"[E] {Name}" : Name;

    Console.WriteLine($"[{displayName}] - {Price}G");
    Console.WriteLine($"설명: {Description}");

    if (AttackBonus != 0)
        Console.WriteLine($"공격력: +{AttackBonus}");
    if (DefenseBonus != 0)
        Console.WriteLine($"방어력: +{DefenseBonus}");
    if (HealthBonus != 0)
        Console.WriteLine($"체력: +{HealthBonus}");

    Console.WriteLine("------------------------");
}

🎓 배운 점

  • 콘솔 환경에서도 창의적으로 정보를 표현할 수 있다는 걸 알게 됐어요.
  • 작은 변화지만 사용자 경험(UX)에 큰 영향을 줄 수 있다는 걸 느꼈습니다.

5. 상태 저장과 씬 전환 관리

🔧 문제 상황

게임은 여러 화면(씬)으로 구성되잖아요? 메인 메뉴, 상점, 인벤토리 등에서 이동할 때 데이터가 일관되게 유지되지 않아서 큰 문제였어요.

🧪 시도한 해결책

각 씬에서 필요한 데이터를 따로 복사해서 썼는데, 이러면 한 곳에서 바꿔도 다른 곳에는 반영이 안 돼서 문제였어요.

✅ 최종 해결책

  • GameScene이라는 추상 클래스를 만들고 모든 씬이 이걸 상속받도록 했어요.
  • Game 클래스가 Player, Inventory, Shop을 중앙에서 관리하게 했어요.
  • 각 씬은 필요한 객체만 받아와서 사용하게 했습니다.
abstract class GameScene
{
    public string SceneName { get; protected set; }

    public virtual void Initialize()
    {
        Console.Clear();
    }

    public abstract void Run();

    public virtual void Exit()
    {
        Console.WriteLine($"{SceneName} 씬을 종료합니다...");
        Console.WriteLine("계속하려면 아무 키나 누르세요...");
        Console.ReadKey();
    }

    protected int GetUserInput(int min, int max)
    {
        int input;
        bool isValid = false;

        do
        {
            Console.Write("선택: ");
            isValid = int.TryParse(Console.ReadLine(), out input);
            isValid = isValid && input >= min && input <= max;

            if (!isValid)
                Console.WriteLine($"잘못된 입력입니다. {min}에서 {max} 사이의 값을 입력하세요.");

        } while (!isValid);

        return input;
    }
}

🎓 배운 점

  • 추상 클래스와 상속을 이용하면 중복 코드 없이 일관된 로직을 유지할 수 있어요.
  • 데이터 일관성을 유지하려면 중심이 되는 클래스가 꼭 필요하다는 걸 느꼈어요.

6. 사용자 입력 검증과 예외 처리

🔧 문제 상황

플레이어가 숫자가 아니라 글자를 입력하거나, 선택지에 없는 번호를 입력했을 때 프로그램이 꺼지거나 이상해지는 일이 많았어요.

🧪 시도한 해결책

try-catch를 써봤지만 모든 경우를 막기엔 부족했어요.

✅ 최종 해결책

GetUserInput() 메서드를 만들어서 입력값을 범위 안에 있는지 체크하고, 잘못된 입력이면 다시 물어보는 방식으로 처리했어요.

private int GetUserInput(int min, int max)
{
    int input;
    bool isValid = false;

    do
    {
        Console.Write("선택: ");
        isValid = int.TryParse(Console.ReadLine(), out input);
        isValid = isValid && input >= min && input <= max;

        if (!isValid)
            Console.WriteLine($"잘못된 입력입니다. {min}에서 {max} 사이의 값을 입력하세요.");

    } while (!isValid);

    return input;
}

🎓 배운 점

  • 예외를 막기 위한 "방어적 프로그래밍"이 정말 중요하다는 걸 알게 됐어요.
  • 이런 기능은 메서드로 따로 빼두면 여기저기 재사용할 수 있어서 편합니다!

7. "육군 아미타이거" 디버그 모드 구현

🔧 문제 상황

게임 기능 테스트할 때 매번 골드를 늘리거나 장비를 추가하려고 코드를 일일이 바꾸는 게 너무 귀찮았어요.

🧪 시도한 해결책

직접 코드에 숫자를 바꾸는 방법은 너무 비효율적이었어요.

✅ 최종 해결책

입력이 잘못되거나 빈 문자열이면 자동으로 디버그 직업 "육군 아미타이거"를 선택하게 했고, 이 직업은 아주 강한 장비와 골드를 갖고 시작합니다.

case "육군 아미타이거":
    inventory = new Inventory(5000);

    Item k2 = new Item("K2 소총", "대한민국 군인의 주력 소총입니다.", 2000, ItemType.Weapon, 20, 0, 0);
    Item k2c1 = new Item("K2C1 소총", "개량형으로 더 강력한 무기입니다.", 3000, ItemType.Weapon, 25, 0, 0);

    Item gasMask = new Item("K3 방독면", "화생방 방어용 장비.", 1000, ItemType.Armor, 0, 25, 0);
    Item bodyArmor = new Item("레벨3 방탄복", "방어력이 높은 장비.", 2000, ItemType.Armor, 0, 25, 0);
    Item helmet = new Item("경량 방탄헬멧", "가벼우면서 튼튼한 헬멧.", 1500, ItemType.Armor, 0, 25, 0);

    inventory.AddItem(k2);
    inventory.AddItem(k2c1);
    inventory.AddItem(gasMask);
    inventory.AddItem(bodyArmor);
    inventory.AddItem(helmet);
    break;

🎓 배운 점

  • 디버그 모드는 개발자에게 정말 큰 도움이 됩니다.
  • 숨겨진 기능처럼 만들면 플레이어도 재미있게 느낄 수 있어요!

8. 열거형(Enum)과 객체 타입 관리

🔧 문제 상황

아이템 타입(무기/방어구/소비품 등)을 문자열로 관리하다 보니 오타가 나거나 잘못된 비교가 생겨서 버그가 생겼어요.

🧪 시도한 해결책

"Weapon", "Armor"처럼 문자열을 쓰니까 IDE에서 자동완성도 안 되고, 실수도 많았어요.

✅ 최종 해결책

enum을 써서 타입을 명확하게 지정했어요. 덕분에 자동완성도 되고, 오타도 줄고, 가독성도 좋아졌습니다.

public enum ItemType
{
    Weapon,
    Armor,
    Consumable
}

🎓 배운 점

  • enum은 초보자라도 꼭 써야 하는 좋은 기능이에요.
  • 코드가 안전해지고 보기 좋아집니다!

 

🎮 스파르타 던전 프로젝트 트러블슈팅 정리


🔧 주요 클래스 구조

  • 게임의 전체 진행을 총괄하는 "중앙 관리자" 역할이에요.
  • 플레이어, 인벤토리, 상점 같은 객체를 생성하고 서로 연결해줘요.
  • 씬(Scene) 간 전환도 이 클래스에서 담당해요.
  • 사용자 입력을 받을 때 GetUserInput() 같은 검증 메서드도 가지고 있어요.

📌 Player 클래스

  • 플레이어의 이름, 직업, 능력치(공격력, 방어력, 체력)를 저장해요.
  • 직업에 따라 시작 능력치가 달라지고, 장착한 아이템에 따라 능력치가 변동돼요.
  • DisplayStatus() 메서드로 플레이어 상태를 보여줄 수 있어요.

📌 Item 클래스

  • 모든 아이템의 속성(이름, 설명, 가격, 타입, 능력치 보너스 등)을 저장해요.
  • 장착 여부를 관리하는 IsEquipped 속성이 있어요.
  • DisplayInfo() 메서드로 아이템 정보를 예쁘게 출력해요.

📌 Inventory 클래스

  • 플레이어가 가진 아이템 리스트를 저장해요.
  • 골드를 저장하고 사용하는 메서드도 있어요.
  • 아이템 장착/해제 기능이 포함되어 있어요.
  • DisplayInventory()로 현재 인벤토리 내용을 볼 수 있어요.

📌 Shop 클래스

  • 상점에서 판매할 아이템 리스트를 가지고 있어요.
  • 아이템을 사거나 팔 수 있는 기능이 있어요 (BuyItem(), SellItem()).
  • 판매 가격은 구매 가격의 절반으로 계산돼요.

📌 GameScene (추상 클래스)

  • 공통적인 씬 동작을 정의한 "틀(template)" 같은 역할이에요.
  • Initialize(), Run(), Exit() 같은 기본 동작이 들어있어요.
  • 씬마다 다르게 동작하는 부분은 Run()에서 구체적으로 구현해요.

📌 구체적인 씬 클래스들

  • StartScene: 게임 시작화면 + 직업 선택.
  • StatusScene: 플레이어 능력치 확인.
  • InventoryScene: 인벤토리 확인 및 장착/해제.
  • ShopScene: 상점에서 아이템 사고팔기.
  • DungeonScene: 전투 및 보상 (개발 중).

🔧 기능 구현 요약

  • 플레이어 이름을 입력하고, 직업을 선택해요.
  • 기본 직업: 전사(검 + 갑옷), 마법사(지팡이 + 로브), 궁수(활 + 조끼).
  • 디버그 직업: "육군 아미타이거" → 고성능 장비 + 많은 골드 지급.

🎒 인벤토리 시스템

  • 아이템 추가/삭제 가능.
  • 아이템 장착/해제 → 능력치 반영됨.
  • 골드 부족 시 구매 실패 메시지 출력.
  • 장착된 아이템은 [E] 표시로 확인 가능.

🛒 상점 시스템

  • ShopScene에서 아이템 목록 확인 후 구매/판매 가능.
  • 판매 시 가격은 원래 가격의 절반으로 책정됨.
  • 골드가 부족하면 구매할 수 없음.
  • 다양한 아이템 구성 (무기, 방어구, 소비품).

📊 상태 확인 시스템

  • 플레이어 이름, 직업, 능력치를 모두 출력.
  • 장착된 아이템과 그 효과도 함께 보여줌.
  • 능력치는 기본 능력치 + 장비 보너스로 계산.

🗡️ 던전 시스템 (개발 중)

  • 난이도 선택 가능 (쉬움, 일반, 어려움).
  • 전투 결과에 따라 보상 획득 or 체력 감소.
  • 랜덤 아이템 드랍 시스템 구현 예정.

🚀 향후 개선 사항 및 개발 계획

  • 코드 중복 줄이기 (공통 메서드는 별도로 만들기)
  • 예외 처리 강화 (잘못된 입력 처리)
  • 콘솔 UI 더 보기 좋게 만들기 (색상, 구분선 등)
    • 특히 요정대사에 색상 넣고 싶다. 내 구글링이 좀만 더 우월했어도....
  • 저장/불러오기 기능 도입 (파일로 저장 예정...아...마?)

🧱 앞으로 만들 기능들

  • 던전 시스템 완성 (적을 만들기 보단. 일단. 시뮬레이션 식. 즉 난이도를 누르면 랜덤하게 체력 다운 등. 아니다, 피로도를...구현해버릴까?
  • 경험치/레벨업 시스템 추가
  • 휴식 시스템 추가(여관으로 만들기!)
  • 스킬 시스템 추가 (직업별 고유 스킬)
  • 간단한 스토리 이벤트 삽입