본문 바로가기
게임 프로그래밍/유니티 활용

[유니티 활용] ScriptableObject 를 이용한 Item Drop Table 만들기

by 레오란다 2023. 4. 25.
반응형

이번 글에서는 몬스터 사냥, 상자 열기, 스테이지 클리어 보상 등 거의 모든 게임에서 필요한 아이템 드랍을 ScriptableObject 를 이용해 구현하는 방법에 대해 알아보도록 하겠습니다.

 

 

Item 정의

ScriptableObject 를 이용해 다음과 같이 Item 정보를 정의해 줍니다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu]
public class SOItem : ScriptableObject
{
   public string itemName;
   public int level;

   [System.Serializable]
   public struct STAT
   {
      public string name;
      public int value;
   }

   public List<STAT> stats = new List<STAT>();

   public int maxStack;
   public int price;

   public Sprite icon;
   public Transform prefab;

   [Multiline]
   public string description;
}

여기서 prefab 은 몬스터등을 잡고 난 후 몬스터가 죽은 자리에 떨어진 아이템을 표시할 때 사용할 prefab을 연결하면 됩니다.

 

SOItem 을 이용해 Item 을 생성한 예

 

여기서는 Prefab 과 Icon 에 아무것도 연결하지 않았지만 실제 사용할 땐 연결해 주셔야 합니다. Icon 은 인벤토리와 같이 아이템을 아이콘 형태로 보여줄 때 사용하면 됩니다.

 

Item Drop Table 만들기

ScriptableObject 를 이용한 Item Drop Table 은 다음과 같이 만들 수 있습니다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

[CreateAssetMenu]
public class SOItemDropTable : ScriptableObject
{
   [System.Serializable]
   public class Items
   {
      public SOItem item;
      public int weight;
   }

   public List<Items> items = new List<Items>();

   protected SOItem PickItem()
   {
      int sum = 0;
      foreach (var item in items)
      {
         sum += item.weight;
      }

      var rnd = Random.Range(0, sum);

      for (int i = 0; i < items.Count; i++)
      {
         var item = items[i];
         if (item.weight > rnd) return items[i].item;
         else rnd -= item.weight;
      }

      return null;
   }

   public void ItemDrop(Vector3 pos)
   {
      var item = PickItem();
      if (item == null) return;

      Instantiate(item.prefab, pos, Quaternion.identity);
   }
}

 

이 코드를 이용해 위에서 만든 RedPotion 과 ShortSword 의 Item drop table 을 다음과 같이 만들 수 있습니다.

 

Slime 용 Item drop table 작성 예시

이 코드에서 weight 는 아이템이 drop 될 확률의 가중치입니다. None 은 아이템을 드랍하지 않는 것입니다. 여기서는 아이템이 나오지 않을 확률이 50%, RedPotion 이 나올 확률이 33.3%, ShortSword 가 나올 확률이 16.6% 가 됩니다.

 

 

SOMonster에 연결하기

SOMonster 는 이전 글에서 작성한 것을 사용할 것입니다.

2023.04.24 - [게임 프로그래밍/유니티 활용] - [유니티 활용] ScriptableObject를 이용한 Data 관리 예제 - 몬스터

 

[유니티 활용] ScriptableObject를 이용한 Data 관리 예제 - 몬스터

ScriptableObject 는 데이터 관리 측면에서 굉장히 유용하게 사용할 수 있습니다. 이 글에서는 ScriptableObject 를 이용해 몬스터를 정의하고 객체를 만드는 방법에 대한 예제를 다뤄보도록 하겠습니다.

ugames.tistory.com

 

SOMonster 에 다음과 같이 ItemDropTable 을 추가하도록 하겠습니다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu]
public class SOMonster : ScriptableObject
{
   public int str; // strenth / 힘
   public int dex; // dexterity / 민첩
   public int con; // Constitution / 생명력

   public SOItemDropTable itemDropTable;
}

 

위와같이 코드를 수정하고 다음과 같이 위에서 만든 ItemDropTable 인 IDT_Slime 을 SOMonster 로 만든 Slime 에 연결해 줍니다.

 

 

 

Item Drop 코드

아래의 코드는 이전 글에서 만든 Slime 스크립트에 GetHit 함수를 추가하고 몬스터의 체력이 0 이하가 되면 Item Drop Table 을 이용해 선택된 아이템을 드랍하는 코드가 추가된 것입니다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Slime : MonoBehaviour
{
   public SOMonster soMon;

   public int level;

   [HideInInspector]
   public int hp;

   [HideInInspector]
   public int dmg;

   float attackDelay;

   // Start is called before the first frame update
   void Start()
   {
      hp = level * soMon.con;
      dmg = level * soMon.str;
      attackDelay = 1f / ((soMon.dex + level) * 0.5f);
   }

   public int GetHit(int d)
   {
      hp -= d;
      
      if (hp <= 0)
      {         
         // 몬스터가 죽으면 Item Drop Table 을 이용해 아이템 드랍
         soMon.itemDropTable.ItemDrop(transform.position);
      }

      return hp;
   }
}

 

 

반응형

댓글