How to call a randomized loot table method again from within itself to prevent duplicates in Unity?

Viewed 50

I have a basic loot table with weighted drop rarities. I am trying to make it so that when the game starts, it will re-roll if the item already exists in a duplicated list.

I've created an empty list in shopManagerScript and am adding each instantiated item to that list. Then I would like to check against that list to see if the item exists. If it does, I want to re-roll again. If it doesn't then go ahead and instantiate the item.

This current code is executing endlessly however, and is crashing my game.

public GameObject shopManager;
public ShopManager shopManagerScript;

[System.Serializable]
public class DropItem
{
    public string name;
    public GameObject item;
    public int dropRarity;
}

public List<DropItem> ShopItemPool = new List<DropItem>();

private void Start()
{

    shopManager = GameObject.FindGameObjectWithTag("ShopManager");
    shopManagerScript = shopManager.GetComponent<ShopManager>();
    SpawnItem();
}
void SpawnItem()
{
    int itemWeight = 0;

    for (int i = 0; i < ShopItemPool.Count; i++)
    {
        itemWeight += ShopItemPool[i].dropRarity;
    }

    int randomValue = Random.Range(0, itemWeight);

    for (int i = 0; i < ShopItemPool.Count; i++)
    {
        if (randomValue <= ShopItemPool[i].dropRarity && !shopManagerScript.shopItems.Contains(ShopItemPool[i].item.ToString()))
        {
            Instantiate(ShopItemPool[i].item, transform.position, Quaternion.identity);
            shopManagerScript.shopItems.Add(ShopItemPool[i].item.ToString());
            return;
        }
        else
        {
            SpawnItem();
        }

        randomValue -= ShopItemPool[i].dropRarity;
    }
}
1 Answers

The problem here is that SpawnItem method calls SpawnItem inside the for, which results in having more running SpawnItem. Then these running SpawnItem call more SpawnItem. The process continues until stack is overflowed and it falls with StackOverflowException.

In order to fix this you can use continue as mentioned before, but be careful with calling SpawnItem, because if the random keeps generating inappropriate values the method can still be called too many times and the error will be the same.

Another way to fix it is to remove recursive call of it and make another method that loops calling SpawnItem. Just make sure that the logic of looping doesn't fully rely on random, otherwise it's still possible to call the method too many times

Related