3 분 소요

Intro

이번 포스팅에서는 방어구아이템을 추가하고, 방어구를 장착/해제할 수 있는 기능을 구현해보았습니다.

방어구는 상의(Top), 장갑(Gloves), 신발(Shoes) 데이터만 먼저 추가하기로 했습니다.

ArmorData.json 이름으로 방어구 데이터를 만들어 주었습니다.

파츠별 데이터는 카테고리를 만들어주었습니다.

{
    "Top": [
        {
            "id": 3001,
            "itemName": "낡은 갑옷",
            "itemToolTip": "낡은 갑옷이다.",
            "itemIcon": "Item_ArmorItem_Top_01.png",
            "defense": 5,
            "type": "Top"
        },
        {
            "id": 3002,
            "itemName": "단단한 갑옷",
            "itemToolTip": "단단한 갑옷이다.",
            "itemIcon": "Item_ArmorItem_Top_02.png",
            "defense": 10,
            "type": "Top"
        }
    ],
    "Shoes": [
        {
            "id": 4001,
            "itemName": "낡은 장화",
            "itemToolTip": "낡은 신발이다.",
            "itemIcon": "Item_ArmorItem_Shoes_01.png",
            "defense": 3,
            "type": "Shoes"
        },
        {
            "id": 4002,
            "itemName": "판금 장화",
            "itemToolTip": "단단한 신발이다.",
            "itemIcon": "Item_ArmorItem_Shoes_02.png",
            "defense": 6,
            "type": "Shoes"
        }
    ],
    "Gloves": [
        {
            "id": 5001,
            "itemName": "허름한 장갑",
            "itemToolTip": "허름한 장갑이다.",
            "itemIcon": "Item_ArmorItem_Gloves_01.png",
            "defense": 3,
            "type": "Gloves"
        },
        {
            "id": 5002,
            "itemName": "부드러운 장갑",
            "itemToolTip": "부드러운 장갑이다.",
            "itemIcon": "Item_ArmorItem_Gloves_02.png",
            "defense": 6,
            "type": "Gloves"
        }
    ]
}

방어구는 현재 장착시 방어력만 올라가도록 했습니다.

ArmorItemData 클래스

우선 ArmorItemDTO 클래스를 만들어 데이터를 직렬/역직렬화 할 수 있도록 했습니다.

// ArmorItemDTO.cs
/*
                ArmorItemData 직렬화 전용 클래스
 */
[System.Serializable]
public class ArmorItemDTO
{
    public int id;                      // 아이템 id
    public string itemName;             // 아이템 이름
    public string itemToolTip;          // 아이템 툴팁
    public string itemIcon;             // 아이템 아이콘 이름
    public int defense;                 // 방어력
    public string type;                 // 장비타입
}

그다음, ArmorItemData 클래스를 작성합니다.

// ArmorItemData.cs
/*
                ArmorItemData : 방어구 아이템 데이터
                
                생성자 : 데이터를 받아 초기화
                CreateItem() : 초기화된 데이터로 아이템 객체 생성
 */

public class ArmorItemData : EquipmentItemData
{
    [SerializeField] private int defense;       // 방어력
    [SerializeField] private string type;       // 장비타입

    public int Defense => defense;
    public string Type => type;

    public ArmorItemData(ArmorItemDTO dto)
    {
        this.id = dto.id;
        this.itemName = dto.itemName;
        this.itemToolTip = dto.itemToolTip;
        this.itemIcon = dto.itemIcon;
        this.defense = dto.defense;
        this.type = dto.type;
    }

    public override Item CreateItem()
    {
        return new ArmorItem(this);
    }
}

ArmorItem 클래스

ArmorItem 클래스는 ArmorItemData를 받은 실제 아이템객체가 될것이고, 장비장착 및 해제를 위한 함수가 존재합니다.

장비장착 및 해제는 IEquipableItem 인터페이스를 상속받아 구현하였습니다.

// IEquipableItem.cs
public interface IEquipableItem 
{
    // 장비 장착
    void Equip();

    // 장비 장착 해제
    void Unequip();
}
/*
                ArmorItem : 방어구 아이템
                
                Equip() : 방어구 장착
                    - 방어구 데이터의 수치만큼 플레이어 능력치 상승
                Unequip() : 방어구 해제
                    - 방어구 데이터의 수치만큼 플레이어 능력치 하락
 */

public class ArmorItem : EquipmentItem, IEquipableItem
{
    public ArmorItemData ArmorData { get; private set; }
    public ArmorItem(ArmorItemData data) : base(data)
    {
        ArmorData = data;
    }
    
    public void Equip()
    {
        DataManager.Instance.GetPlayerData().EquipItem(ArmorData.Defense, ArmorData.Type);
    }

    public void Unequip()
    {
        DataManager.Instance.GetPlayerData().UnequipItem(ArmorData.Defense, ArmorData.Type);
    }
}

DataManager 클래스

DataManager 클래스에서 방어구 아이템 데이터를 불러오기위한 작업을 수행합니다.

    // 방어구 데이터 불러오기
    private Dictionary<int, ArmorItemData> LoadArmorData()
    {
        if(File.Exists(armorItemDataPath))
        {
            string jsonData = File.ReadAllText(armorItemDataPath);
            var armorDict = JsonConvert.DeserializeObject<Dictionary<string, List<ArmorItemDTO>>>(jsonData);

            if(armorDict != null)
            {
                foreach(var category in armorDict)  // "Top", "Shoes", "Gloves"
                {
                    Dictionary<int, ArmorItemData> dataDictionary = new Dictionary<int, ArmorItemData>();
                    foreach (var armorDTO in category.Value)
                    {
                        ArmorItemData armorData = new ArmorItemData(armorDTO);
                        dataDictionary[armorData.ID] = armorData;
                    }
                    return dataDictionary;
                }
            }
            else
            {
                Debug.LogWarning("Json 데이터를 파싱할 수 없습니다.");
            }
        }
        else
        {
            Debug.LogWarning("불러올 파일이 없습니다.");
        }
        return new Dictionary<int, ArmorItemData>();
    }

ArmorData.json 파일 안에 몇가지 카테고리가 있고, 그 안에 여러 데이터가 들어있기때문에 foreach 문을 2번 사용하여

데이터를 받아와 저장하였습니다.

이전에 작성한 무기데이터 및 포션데이터를 로드하는 함수도 마찬가지로 바꿔주었습니다.

Inventory 클래스

Inventory 클래스에서는 인벤토리에서 마우스 우클릭을 통해 아이템을 사용할때 호출되는 Use() 함수에서

아이템 장착을 처리하도록 했습니다.

  1. 사용자가 인벤토리내의 아이템을 마우스 우클릭

  2. Inventory 클래스에 아이템 사용 요청(Use() 호출)

  3. Use() 함수에서 아이템 종류(소비, 장비 등)에 따른 아이템 사용 진행
    • 이미 장착중인 장비가 있다면, 착용중인 장비를 장착해제
    • 캐릭터 정보창의 아이템 아이콘을 제거한 뒤, 인벤토리에 장착해제한 아이템 추가
    • 그 다음, 장비 장착 - 인벤토리내 아이템 제거 및 캐릭정보창에 아이템 등록
  4. 성공시 인벤토리 업데이트
    // 해당 슬롯 인덱스의 아이템 사용
    public void Use(int index)
    {
        if (!IsValidIndex(index)) return;
        if (items[index] == null) return;

        // 1. 소모 아이템일 때
        if(items[index] is IUsableItem usable)
        {
            // 사용
            bool success = usable.Use();

            // 성공
            if(success)
            {
                UpdateSlot(index);
            }
        }
        // 2. 장비 아이템일 때
        else if(items[index] is IEquipableItem equipable)
        {
            // 2.1. 무기 아이템일때 
            if(equipable is WeaponItem)
            {
                // 장착중인 아이템이 있으면 해제
                if (equipmentUI.slotUIList[0].HasItem)
                {
                    // 장착중인 아이템
                    WeaponItem prevItem = (WeaponItem)equipmentUI.items[0];
                    // 인벤토리에 장착중이던 아이템 추가
                    AddItem(prevItem.Data);
                    // 캐릭터 정보창 슬롯의 아이콘 제거
                    equipmentUI.slotUIList[0].RemoveItemIcon();
                    // 장착 해제
                    prevItem.Unequip();
                }
                // 새롭게 장착할 아이템
                WeaponItem curItem = (WeaponItem)items[index];
                // 장착 및 캐릭터 정보창 슬롯 아이콘 등록
                equipable.Equip();
                equipmentUI.SetItemIcon(curItem,curItem.WeaponData.Type, curItem.Data.ItemIcon);
            }
            // 2.2 방어구 아이템일때
            else if(equipable is ArmorItem)
            {
                
            }
            Remove(index);
            UpdateSlot(index);
        }
    }

image

댓글남기기