#Weighted Randomiser - Loot Table

1 messages · Page 1 of 1 (latest)

delicate jolt
#

I am trying to implement a shop system where in these two cards upgrades are randomly slotted. I have so far implemented a Randomiser which randomly picks from an Array of "Scriptable Objects" all of which have their own "DropChance". It is working so far.

However the problem is it keeps picking the same items for both of the Cards. Instead I want it to "Remove" the item from the item pool, that has already been picked and run the For Loop without it.

#

Here is my code:

#
 public List<UpgradeItem> upgradeItems = new List<UpgradeItem>();

    int totalWeight = 0;

    UpgradeItem GetUpgradeItem()
    {
        int randomItem = Random.Range(1, 101);

        List<UpgradeItem> possibleUpgrades = new List<UpgradeItem>();

        foreach (UpgradeItem item in upgradeItems)
        {

            if (randomItem <= item.upgradeDropChance)
            {
                possibleUpgrades.Add(item);
                Debug.LogWarning("Added To List: " + item.name);
            }
        }

        if (possibleUpgrades.Count > 0)
        {
            UpgradeItem pickedUpgrade = possibleUpgrades[Random.Range(0, possibleUpgrades.Count)];
            return pickedUpgrade;
        }
        return null;
    }


    public void ShowUpgrades()
    {
        UpgradeLogic[] upgradeContainer = FindObjectsOfType<UpgradeLogic>();

        foreach (UpgradeLogic upgrade in upgradeContainer)
        {
            UpgradeItem pickedUpgrade = GetUpgradeItem();

            for (int i = 0; i < upgradeContainer.Length; i++)
            //for getting reference to the Text Boxes inside the Upgrade Card
            {
                PrefabCompHolder compHolder = upgrade.GetComponent<PrefabCompHolder>();
                //string upgradeName = pickedUpgrade.upgradeName; //"Upgrade 1";
                compHolder.nameText.text = pickedUpgrade.name.ToString();
                //string upgradeDescriptor = pickedUpgrade.upgradeDescriptor;
                compHolder.describeText.text = pickedUpgrade.upgradeDescriptor.ToString();
            }

        }
    }
topaz crow
#

If you run the function once and assign it both slots, you'll get the same card since it only returned one card.

delicate jolt
#

I have Another Array which has a reference for the Card GameObjects and I am trying to run the UpgradeItem for each of the Cards within the Array

true shale
#

The code above does not seem to actually use weights to pick?

topaz crow
topaz crow
true shale
#

Yea which is not the desired result. Ive done this kind of stuff before

#

You want to calculate the total weight. Pick a random number in the 0-max range. Then loop over and tally up the weights as you go. Once you go over the random weight (or hit the very end) then you pick this element.

topaz crow
#

I guess this approach works as well if they want a 1-1-1.. chance per card within threshold.

Anyway. If ShowUpgrades() is actually assigning the card to the slots, it makes sense that it would show the same card on both slots when you fetch the card before you do the for loop.
If whatever is within the for loop populates your slots, you might want to try moving UpgradeItem pickedUpgrade = GetUpgradeItem(); into the loop

#

I'd do that first and see if that works.

true shale
#

I always go with the method I just mentioned because it means weights are all relative to each other and picking works with any input "pool"

topaz crow
#

That's understandable. It's just none of my business how they handle the randomness logic 😅

delicate jolt
#

Okay so I am very new to this thing...I just implemented some of it by whatever knowledge I had about Random.Range and For loops

#

There isnt any intention other than that so I am happy to change it

#

Whatever you say will be a better way to make it soo that its picking within the arrray and then discard the choice already picked

delicate jolt
#

but I was getting some errors

#

This is the UpgradeItem Scriptable Object that holds these refs:


public class UpgradeItem : ScriptableObject
{
    public Sprite upgradeIcon;

    public String upgradeName;
    [TextArea] public String upgradeDescriptor;

    public int upgradeDropChance;
}

delicate jolt
#

but I did not know what to do after that

true shale
#

Let me write an example

#
public static Thing GetItemWithRandomWeight(IList<Thing> things)
{
    float totalWeight = 0f;
    foreach (var item in things)
    {
        totalWeight += item.weight;
    }

    float randomWeight = Random.Range(0f, totalWeight);
    float cumulativeWeight = 0f;

    foreach(var thing in things)
    {
        cumulativeWeight += thing.weight;
        if(cumulativeWeight >= randomWeight)
        {
            return thing;
        }
    }

    //Fallback to last item
    return things[things.Count - 1];
}
delicate jolt
#

umm what is IList??

#

I havent encountered that one yet

true shale
#

Its an interface that both List and array implement

#

you can use List there or an array if you want

delicate jolt
#

oh okay interesting

#

I'll learn about it

#

also I am guessing the ``public static Thing` is a reference to the Scriptable Object code? or is it a reference to the code attached to the Cards?

true shale
#

Thing is just what i decided to call whatever your main type is

#

static makes this a static method. If that confuses you then you can go research what the static keyword does in c#

delicate jolt
#

alright

#

thank you

#

a lot

#

I learned a lot

delicate jolt
# true shale ``Thing`` is just what i decided to call whatever your main type is

umm how can I create a definition for .weight in my ScriptableObject Code?

 public static UpgradeItem GetItemWithRandomWeight(IList<UpgradeItem> things)
    {
        float totalWeight = 0f;
        foreach (var item in things)
        {
            totalWeight += item.weight*;
        }

*It is throwing an error: 'UpgradeItem' does not contain a definition for 'weight' and no accessible extension method 'weight' accepting a first argument of type 'UpgradeItem' could be found (are you missing a using directive or an assembly reference?)CS1061
#

Should it be float or int?

true shale
#

Either works but float means not being restricted to ints