[ C# ] 플레이어 인벤토리 구현

2024. 3. 16. 21:13C#/구현

구현 목록

1. 캐릭터의 일반 인벤토리 생성

  • 캐릭터가 게임을 진행 중에 얻은 아이템을 저장하는 공간을 제작.
  • Dictionary를 사용하여 아이템의 타입을 분류.
    • 아이템 타입 : 소모품, 무기, 방어구
  • 이미 가지고 있는 아이템을 주우면 새롭게 추가(Add)되는 것이 아닌 개수(count)를 조정.
  • 만약 가지고 있지 않은 아이템을 주우면 새로 추가(Add)
  • 포션을 사용하면 지정된 수치만큼 캐릭터의 HP를 증가.
  • 무기와 방어구를 지정하고 사용하면 장비 인벤토리에서 장착, 또는 해제되도록 설정

2. 캐릭터의 착용 장비 인벤토리 생성

  • 캐릭터가 장비를 착용하면 해당 장비를 저장하는 공간을 제작.
  • Dictionary를 이용하여 아이템의 착용 부위를 분류.
    • 분류 타입 : 무기, 머리, 갑옷, 다리
  • 해당 부위에 장비를 착용하고 있으면 다른 아이템 착용 불가.
  • 장비를 장착하면 해당 장비의 능력치만큼 캐릭터의 능력치가 증가.
  • 장비를 해제하면 해당 장비의 능력치만큼 캐릭터의 능력치 감소.

작성한 코드는 Git으로 이동하여 확인하기를 바란다.

Git 주소 : https://github.com/KimJinMyung/2024_03_16_MazeTPRG

 

GitHub - KimJinMyung/2024_03_16_MazeTPRG: 3월 16일에 작업한 내용 : 아이템 인벤토리와 장비 인벤토리 제작,

3월 16일에 작업한 내용 : 아이템 인벤토리와 장비 인벤토리 제작, 아이템 사용 및 줍기 구현, 인벤토리 장비 장착 및 해제 구현 - KimJinMyung/2024_03_16_MazeTPRG

github.com

 


제작하며 어려움을 느낀 점

1. 아이템이 사용되면 그 효과가 현재 조작하고 있는 플레이어 캐릭터에게 적용되도록 하는 것

  • 캐릭터의 정보를 불러와서 처리하려고 하였지만 현재 조작하고 있는 player의 인스턴스를 가져오는 것이 관건이었다.
  • 단순하게 "인벤토리에서 아이템의 효과를 사용한다"라고 만들어도 정작 조작하고 있는 player에게 적용되지 않았다.

해결 방법

플레이어의 인스턴스를 플레이어 내부에서 선언.

플레이어 캐릭터의 클래스가 Player라고 가정하면

Private Static Player playerInstance;라고 작성하여 자기 자신의 인스턴스를 선언했다.

이후, property를 사용하여 인스턴스를 정의하고 어디에서든 호출할 수 있도록 만들어주었다.

public static Player Instance
{
    get
    {
        if (playerInstance == null)
        {
            playerInstance = new Player();
        }return playerInstance;
    }
}

 

2. 아이템의 사용할 때 발생되는 중복을 최대한 줄이는 것.

  • 아이템을 사용할 때, 생각보다 많은 중복이 발생하였다.
  • switch를 사용하면 간단하게 해결되었지만 아이템의 개수가 많아질 경우를 대비해야 할 필요성을 느꼈다.
  • 이에 SOLID 원칙을 지키며 가독성을 높일 수 있게 주의를 기울였다.

해결 방법

아이템을 사용한다는 Use() 메서드를 부모 클래스인 item class에 선언하고 추상화하였다.

그렇게 작성하면 플레이어는 Use() 메소드 하나로 모든 아이템의 효과를 분류하여 사용할 수 있다.

예를 들어 [포션]은 체력을 회복하고 [단검]은 공격력을 증가시킨다고 가정한다면

추상화를 사용하게 될 경우, 플레이어는 입력받은 아이템에 따라 사용 효과가 정해진다.

 

포션 클래스의 사용 메서드

public override bool Use()
{
    Player.Instance.HealHP(this.EffectValue);
    return true;
}

 

아이템을 사용하는 메서드

public bool UseItem(string itemName)
{
    //입력한 텍스트와 같은 name을 가진 아이템이 인벤토리에 존재하면
    foreach (var item in itemInventoryDic)
    {
        if (item.Key.GetName == itemName)
        {                    
            //해당 아이템의 효과를 발동한다.
            //아이템을 사용했거나 장비하였으면 true
            bool UseOrEquip = item.Key.Use();
            if (UseOrEquip)
            {
                //사용한 아이템의 갯수를 줄인다.
                itemInventoryDic[item.Key]--;
                //사용한 아이템의 갯수가 0이하이면 Remove한다.
                if (itemInventoryDic[item.Key] <= 0) { itemInventoryDic.Remove(item.Key); }
                return true;
            }                            
        }
    }
    return false;
}

 

3. 장비의 착용 해제

  • item class에게 Use()라는 메서드를 추상화 형식으로 선언하여 해당 클래스를 상복받는 장비들도 해당 메서드를 사용해야 한다.
  • 그러나 장비는 포션과 같은 소모품과는 달리 착용과 해제, 2가지의 동작이 실행되어야 한다.
  • 그렇다고 메서드를 새롭게 만들어 사용하면 인벤토리의 코드들을 전부 바꿔야 하는 경우가 발생한다.
  • 결국 Use()라는 메서드로 착용과 해제를 모두 구현해야 한다.

해결 방법

내부에 논리 자료형을 선언하여 장착과 해제 메서드를 Use 메서드 내부에서 구분해 사용할 수 있도록 제작하였다.

만약 해당 장비를 처음 호출한다면 착용한다는 메서드를, 두 번이면 해제한다는 메서드를 실행하도록 제작하였다.

 

구현 코드

//장비 착용
public void Equip()
 {
     equiped = true;
     Player.Instance.Equip(this.Parts, this);
     Player.Instance.WeaponsATK(EffectValue);
 }
//장비 해제
 public void UnEquip()
 {
     equiped = false;
     Player.Instance.UnEquip(this.Parts);
     Player.Instance.WeaponsATK(-EffectValue);
 }
//착용과 해제를 구분하여 사용한다.
 public override bool Use()
 {
     if (!equiped)
     {
         Equip();
         return true;
     }
     else
     {
         UnEquip();
         return false;
     }
 }

 

4. 장비의 능력치 적용

  • 장비를 장착하고 해제하는 것에는 성공했지만 해당 아이템의 능력치를 캐릭터에게 반영하는 것에서 다시 고전하였다.
  • 단순히 플레이어의 능력치를 조정시켜 주는 메서드를 호출하면 된다고 생각하였다.
  • 그러나 실행해 보니 장비를 해제하였을 때, 장비의 능력치가 캐릭터에서 빠져나가지 않고 오히려 더 증가시키는 현상이 발생하였다.

해결 방법

아이템을 장착하였을 때, 새롭게 아이템을 선언하여 장비 인벤토리에 전송한 것이 문제였다.

캐릭터의 인스턴스를 불러온 것처럼 선언하였을 경우, 실행되는 속도가 느려질 것이 우려되었다.

이에 새롭게 아이템을 선언하는 것이 아닌 this를 이용하였다.

 

public void Equip()
{
    equiped = true;
    Player.Instance.Equip(this.Parts, this);
    Player.Instance.WeaponsATK(EffectValue);
}

public void UnEquip()
{
    equiped = false;
    Player.Instance.UnEquip(this.Parts);
    Player.Instance.WeaponsATK(-EffectValue);
}

 


더욱 간단하게 작성할 수 있을 것이라고 생각할 수도 있지만 작업 도중 아이템이 추가될 때, 큰 어려움이 없도록 유연성을 증가시키는 것에 중점을 두었다고 생각해 주었으면 좋겠다;;

'C# > 구현' 카테고리의 다른 글

[ C# ] Stack 과 Queue 구현  (0) 2024.03.13
[ C# ] 미로 게임 구현  (0) 2024.03.09