I made a Loot and Item system earlier and thought it was brilliant so I decided to share it. Lets get into it.
We need a ItemDatabase class that holds data of all items. We have a basic Item class that contains data of a single item. Then we have a constructor that deep copies our item, so holding multiple same items would work and different same items would act as individual instead of being a shallow copies of the main one.
ItemDatabase has two static methods that returns you item based on name or id.
using UnityEngine; using System.Collections; using System.Collections.Generic; public class ItemDatabase : MonoBehaviour { public List<Item> allItems; public static List<Item> items; [System.Serializable] public class Item { public string itemName = ""; public int itemID = 0; public int dmg = 0; public int armor = 0; public Sprite icon; public enum Type { equipment, other } public enum Rarity { common, uncommon, rare, epic } public Type type; public Rarity rarity; public Item() { } public Item(Item itemCopy) { itemID = itemCopy.itemID; icon = itemCopy.icon; itemName = itemCopy.itemName; dmg = itemCopy.dmg; armor = itemCopy.armor; } } private void Awake() { InitItems (); } private void InitItems() { items = allItems; } public static Item GetItemByName(string itemName) { for( int i = 0;i<ItemDatabase.items.Count;i++ ) { if(ItemDatabase.items[i].itemName == itemName) { return ItemDatabase.items[i]; } } return null; } public static Item GetItemById(int id) { for( int i = 0;i<ItemDatabase.items.Count;i++ ) { if(ItemDatabase.items[i].itemID == id) { return ItemDatabase.items[i]; } } return null; } }
Then we have a Loot class. This is attached to anything that drops loot. Loot class spawns a loot prefab which holds the dropped item, so player can pick it up. In Loot class you can specify which drop % the items have and what items the enemy drops. When enemy dies we call DropItems method. In that method we basically roll a dice for every item drop possibility that the enemy has. Then we check on which gap the roll landed into.
For example we have a loot table like this:
Sword 25%
Staff 15%
Potion 45%
Nothing 55%
Total 140%
We first add all those drop percentages together and get a total value. The value of 140. Now we need to take all the % values from 140 and add them together to get the maximum value. So 25% from 140 is 35 then we add 15% to it which is 21 and so on, until we get the maximum value of 196.
25% 35
15% 21
45% 63
55% 77
140% 196
Now when we roll between 0 and maximum value, we can check if roll land between 0 and 35 if it does we give player a sword. Next item to check is a staff, if player rolled between 35 and 56 we give player a staff. Now if player rolls 145 for example we don’t give him anything as the roll landed between nothing gap etc.
using UnityEngine; using System.Collections; public class Loot : MonoBehaviour { private Transform m_transform; private int m_amountToDrop; public NewPickUp pickUpPrefab; public int minAmountOfDrops, maxAmountOfDrops; [System.Serializable] public class DropItem { public bool empty; public string itemName; public int amount; public bool randomizeAmount; public int min,max; public float dropChance; } public DropItem[] itemsToDrop; private float maximumPropability; private void Start() { m_transform = transform; m_amountToDrop = Random.Range( minAmountOfDrops,maxAmountOfDrops ); InitItemChances (); } /// <summary> /// Initializes drop chances /// </summary> private void InitItemChances() { for( int i = 0;i<itemsToDrop.Length;i++ ) { if(i != 0) { itemsToDrop[i].dropChance += itemsToDrop[i - 1].dropChance; } } maximumPropability = itemsToDrop[itemsToDrop.Length - 1].dropChance; for( int i = 0;i<itemsToDrop.Length;i++ ) { int temp = System.Convert.ToInt32(((maximumPropability / 100) * itemsToDrop[i].dropChance)); itemsToDrop[i].dropChance = (float)temp; } maximumPropability = itemsToDrop[itemsToDrop.Length - 1].dropChance; } /// <summary> /// Drops the items. /// </summary> public void DropItems() { for( int i = 0;i<m_amountToDrop;i++ ) { int rnd = Random.Range(0,(int)maximumPropability + 1); DropItem droppedItem = ChooseItem(rnd); if( !droppedItem.empty ) { SpawnItem(droppedItem); } } } /// <summary> /// Spawns item. /// </summary> /// <param name="droppedItem">Dropped item.</param> public void SpawnItem(DropItem droppedItem) { NewPickUp temp = GameObject.Instantiate( pickUpPrefab,m_transform.position,Quaternion.identity ) as NewPickUp; temp.itemName = droppedItem.itemName; if(droppedItem.randomizeAmount) temp.amount = Random.Range(droppedItem.min,droppedItem.max); else temp.amount = 1; temp.SetUp(); } /// <summary> /// Choose item to drop by its drop chance /// </summary> /// <returns>The item.</returns> /// <param name="rnd">Random.</param> public DropItem ChooseItem(int rnd) { int maxVal = (int)itemsToDrop [itemsToDrop.Length - 1].dropChance; if(rnd == maxVal) rnd -= 1; int index = 0; while (itemsToDrop[index].dropChance <= rnd) { index++; } return itemsToDrop [index]; } }
Here is the pickup class. This class is spawned into the world as a prefab. If player steps on it we take the item to our inventory if we have space.
using UnityEngine; using System.Collections; public class NewPickUp : MonoBehaviour { public string itemName; public int amount; private void Start() { SetUp(); } public void SetUp() { Item item = ItemDatabase.GetItemByName( itemName ); if(item != null) { GetComponent<SpriteRenderer>().sprite = item.icon; } } private void OnTriggerEnter2D(Collider2D col) { if (col.GetComponent<Inventory> ()) { Inventory inv = col.GetComponent<Inventory> (); //We need to create deep copy from the item, so we can have multiple same items. ItemDatabase.Item newItem = new ItemDatabase.Item(item); if(newItem != null) { for(int i = 0;i<amount;i++) { if(!inv.IsFull(newItem)) { inv.AddItem(newItem); amount--; } } } if(amount == 0) { Destroy(gameObject); } } } }
I didn’t include my Inventory class, because it’s mostly about how the Inventory UI works. It contains 2 lists of itemslots. One for equipped items and one for inventory itself. Then you just do some kind of equipping system and handle all the checks such as; if your high enough level for the item, add and remove stats etc etc.
Thanks for reading and hope this helps someone.