유니티 아이템 사용 - yuniti aitem sayong

Date: 2020.10.05    Updated: 2020.10.05

카테고리: Unity Lesson 3

태그: Unity Game Engine

인프런에 있는 케이디님의 [유니티 3D] 실전! 생존게임 만들기 - Advanced 강의를 듣고 정리한 필기입니다. 😀
🌜 강의 들으러 가기 Click

Chapter 5. 인벤토리

🚖 포션 아이템 만들기

이름은 Potion Yellow Item

  • “Item” 태그, 레이어
  • Box Collider
  • Rigidbody
  • 📜ItemPickUp
    • Potion Yellow item 만들어서 할당
      • 아이템 타입은 Used

🚖 포션 먹으면 회복하게 하기

인벤토리에서 해당 포션에 우클릭하면 소모되도록 한다.

📜ItemEffectDatabase.cs

빈 오브젝트 Database를 만들고 📜ItemEffectDatabase.cs 을 붙여 주었다.

using System.Collections; using System.Collections.Generic; using UnityEngine; [System.Serializable] public class ItemEffect { public string itemName; // 아이템의 이름(Key값으로 사용할 것) [Tooltip("HP, SP, DP, HUNGRY, THIRSTY, SATISFY 만 가능합니다.")] public string[] part; // 효과. 어느 부분을 회복하거나 혹은 깎을 포션인지. 포션 하나당 미치는 효과가 여러개일 수 있어 배열. public int[] num; // 수치. 포션 하나당 미치는 효과가 여러개일 수 있어 배열. 그에 따른 수치. } public class ItemEffectDatabase : MonoBehaviour { [SerializeField] private ItemEffect[] itemEffects; private const string HP = "HP", SP = "SP", DP = "DP", HUNGRY = "HUNGRY", THIRSTY = "THIRSTY", SATISFY = "SATISFY"; [SerializeField] private StatusController thePlayerStatus; [SerializeField] private WeaponManager theWeaponManager; public void UseItem(Item _item) { if (_item.itemType == Item.ItemType.Equipment) { // 장착 StartCoroutine(theWeaponManager.ChangeWeaponCoroutine(_item.weaponType, _item.itemName)); } if (_item.itemType == Item.ItemType.Used) { for (int i = 0; i < itemEffects.Length; i++) { if (itemEffects[i].itemName == _item.itemName) { for (int j = 0; j < itemEffects[i].part.Length; j++) { switch(itemEffects[i].part[j]) { case HP: thePlayerStatus.IncreaseHP(itemEffects[i].num[j]); break; case SP: thePlayerStatus.IncreaseStamina(itemEffects[i].num[j]); break; case DP: thePlayerStatus.IncreaseDP(itemEffects[i].num[j]); break; case THIRSTY: thePlayerStatus.IncreaseThirsty(itemEffects[i].num[j]); break; case HUNGRY: thePlayerStatus.IncreaseHungry(itemEffects[i].num[j]); break; case SATISFY: break; default: Debug.Log("잘못된 Status 부위. HP, SP, DP, HUNGRY, THIRSTY, SATISFY 만 가능합니다."); break; } Debug.Log(_item.itemName + " 을 사용했습니다."); } return; } } Debug.Log("itemEffectDatabase에 일치하는 itemName이 없습니다."); } } }

  • ItemEffect 클래스 👉 한 아이템의 효과.
    • [System.Serializable]로 선언되어서 이 클래스의 멤버들은 MonoBehaviour 을 상속 받는 클래스가 아닌 일반 C# 클래스임에도 불구하고 유니티 인스펙터에 띄워 여기서 값을 할당할 수 있게 되었다.
    • part와 num 의 인덱스는 대응되게 할 것이다. part[2]가 HUNGRY 라면 num[2] 의 원소 값은 HUNGRY 에 대한 수치
    • itemName에 해당하는 하나의 아이템은 part 배열에 속한 부분들에 대한 효과를 가진다. 그에 대응하는 효과 수치는 num 배열에 해당.
  • itemEffects
    • private 으로 선언되었기 때문에 ItemEffect 클래스가 [System.Serializable]긴 하더라도 SerializeField 해주어야 비로소 유니티 인스펙터에 뜨게 된다.
    • 배열이다. 📜ItemEffectDatabase.cs 에서 여러 포션 아이템들을 이 `itemEffects` 배열 멤버에서 한번에 관리 하게 됨.
  • UseItem(Item _item) 아이템 소모시 👉 📜Slot.cs의 우클릭 이벤트에서 처리 했었는데 성능을 위해 이 스크립트로 옮겼다.
    • 아이템이 장비면 장착하고
      • 때문에 📜WeaponManager.cs 가 필요 하다.
        • 다만 Slot과 다르게 Database는 프리팹은 아니기 때문에 FindObejctOfType을 사용하지 않고 직접 할당해주기로 하였다. [SerializeField].
    • 아이템이 소모품이면 👈 포션이 해당 됨
      • 해당 수치에 맞게 효과 적용
        • 인수로 들어온 아이템의 이름이 itemEffects 배열에 있는지를 찾고
        • 찾았다면 해당 아이템의 효과들을 📜StatusController.cs 의 함수들을 호출하여 적용한다.
          • IncreaseHP 등등
        • 모든 효과를 적용했다면 바로 종료. itemEffects 배열에 있는지를 더 찾을 필요가 없으므로.

  • Potion Yellow 아이템을 소비 하면
    • SP 가 500 으로 증가하고
    • HUNGRY 가 100 으로 증가하고
    • THIRSTY 가 100 으로 증가하게끔 하였다.

📜Slot.cs

private ItemEffectDatabase theItemEffectDatabase; void Start() { baseRect = transform.parent.parent.GetComponent<RectTransform>().rect; theInputNumber = FindObjectOfType<InputNumber>(); theItemEffectDatabase = FindObjectOfType<ItemEffectDatabase>(); } // 마우스 클릭 이벤트 public void OnPointerClick(PointerEventData eventData) { if(eventData.button == PointerEventData.InputButton.Right) { if (item != null) { theItemEffectDatabase.UseItem(item); if(item.itemType == Item.ItemType.Used) SetSlotCount(-1); } } }

  • Slot은 프리팹이기 때문에 다른 오브젝트를 FindObjectOfType 로 불러올 수 밖에 없다. 또한 20개나 되기 때문에 인벤토리가 활성화 되어 슬롯도 활성화 될 때, Start() 에서 너무 많은 컴포넌트를 로딩한다면 성능에 문제가 생길 것이다.
    • 따라서 📜Slot.cs 의 📜WeaponManager.cs 를 불러오는 부분을 지웠다. 아래 코드를 지우고 위와 같이 고침. 대신 이와 같은 과정은 📜ItemEffectDatabase 에서 하도록 옮겼다.
    • 수정 전 📜Slot.cs

      public void OnPointerClick(PointerEventData eventData) { if(eventData.button == PointerEventData.InputButton.Right) { if (item != null) { if(item.itemType == Item.ItemType.Equipment) // 👈👈👈👈👈👈👈 { // 장착 StartCoroutine(theWeaponManager.ChangeWeaponCoroutine(item.weaponType, item.itemName)); } else // 👈👈👈👈👈👈👈 { // 소비 Debug.Log(item.itemName + " 을 사용했습니다."); SetSlotCount(-1); } } } }

    • 📜ItemEffectDatabase.cs

      public void UseItem(Item _item) { if (_item.itemType == Item.ItemType.Equipment) // 👈👈👈👈👈👈👈 { // 장착 StartCoroutine(theWeaponManager.ChangeWeaponCoroutine(_item.weaponType, _item.itemName)); } if (_item.itemType == Item.ItemType.Used) // 👈👈👈👈👈👈👈 { // 소비 for (int i = 0; i < itemEffects.Length; i++) { if (itemEffects[i].itemName == _item.itemName) { for (int j = 0; j < itemEffects[i].part.Length; j++) { switch(itemEffects[i].part[j]) { case HP: thePlayerStatus.IncreaseHP(itemEffects[i].num[j]); break; case SP: thePlayerStatus.IncreaseStamina(itemEffects[i].num[j]); break; case DP: thePlayerStatus.IncreaseDP(itemEffects[i].num[j]); break; case THIRSTY: thePlayerStatus.IncreaseThirsty(itemEffects[i].num[j]); break; case HUNGRY: thePlayerStatus.IncreaseHungry(itemEffects[i].num[j]); break; case SATISFY: break; default: Debug.Log("잘못된 Status 부위. HP, SP, DP, HUNGRY, THIRSTY, SATISFY 만 가능합니다."); break; } Debug.Log(_item.itemName + " 을 사용했습니다."); } return; } } Debug.Log("itemEffectDatabase에 일치하는 itemName이 없습니다."); } }

  • 수정 후 📜Slot.cs
    • 무기든 소모품이든, 아이템 사용에 대한 처리를 📜ItemEffectDatabase.cs 의 UseItem 함수에게 전적으로 맡기게 되었다.
      • 대신 해당 아이템이 소모품일 땐 아이템 갯수를 1 감소시키는 처리를 해주었다.

        if(eventData.button == PointerEventData.InputButton.Right) { if (item != null) { theItemEffectDatabase.UseItem(item); if(item.itemType == Item.ItemType.Used) SetSlotCount(-1); } }

🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기

Unity Lesson 3 카테고리 내 다른 글 보러가기

Toplist

최신 우편물

태그