Skip to content

Instantly share code, notes, and snippets.

@Broxzier
Last active December 16, 2024 13:20
Show Gist options
  • Save Broxzier/fd081828dee98105de78303e8f0cda23 to your computer and use it in GitHub Desktop.
Save Broxzier/fd081828dee98105de78303e8f0cda23 to your computer and use it in GitHub Desktop.
Example of how a spawner could skew the chances for objects to spawin in favour of the player, making it more likely to give the objects a player doesn't have while still respecting a base chance.
public class Program
{
public static void Main()
{
// Setup data
var butterfly = new Spawnable("Butterfly");
var bumblebee = new Spawnable("Bumblebee");
var cockroach = new Spawnable("Cockroach");
var spawnPoint = new SpawnPoint();
spawnPoint.AddItem(butterfly, 0.70);
spawnPoint.AddItem(bumblebee, 0.285);
spawnPoint.AddItem(cockroach, 0.015);
var inventory = new Inventory();
//inventory.AddItem(butterfly, 15);
//inventory.AddItem(bumblebee, 6);
//inventory.AddItem(cockroach, 1);
// Use the spawner to spawn an item
// Despite the cockroach having a 1.5% chance of spawning, the amount of butterflies and bumblebees
// raises its chance to roughly 6%.
var spawner = new Spawner();
for (int i = 0; i < 10000; i++)
{
var spawnedItem = spawner.SpawnItem(spawnPoint, inventory);
inventory.AddItem(spawnedItem);
}
Console.WriteLine($"Spawned {inventory.GetItemCount(butterfly)/100.0}% butterflies");
Console.WriteLine($"Spawned {inventory.GetItemCount(bumblebee)/100.0}% bumblebees");
Console.WriteLine($"Spawned {inventory.GetItemCount(cockroach)/100.0}% cockroaches");
}
}
/// <summary>
/// Represents a spawnable item.
/// </summary>
public class Spawnable
{
public string Name { get; }
public Spawnable(string name)
{
Name = name;
}
}
/// <summary>
/// Represents a spawn point that holds items with their base chances.
/// </summary>
public class SpawnPoint
{
private readonly List<(Spawnable Item, double BaseChance)> _items = new List<(Spawnable, double)>();
public IReadOnlyList<(Spawnable Item, double BaseChance)> Items => _items;
public void AddItem(Spawnable item, double baseChance)
{
_items.Add((item, baseChance));
}
}
/// <summary>
/// Holds the player's inventory counts.
/// </summary>
public class Inventory
{
private readonly Dictionary<Spawnable, int> _itemCounts = new Dictionary<Spawnable, int>();
public void AddItem(Spawnable item, int count = 1)
{
if (_itemCounts.ContainsKey(item))
_itemCounts[item] += count;
else
_itemCounts[item] = count;
}
public int GetItemCount(Spawnable item)
{
return _itemCounts.TryGetValue(item, out var value) ? value : 0;
}
}
/// <summary>
/// Handles the logic of spawning an item from a spawn point, adjusted by inventory.
/// </summary>
public class Spawner
{
private const double SkewFactor = 2.0;
private readonly Random _random = new Random();
public Spawnable SpawnItem(SpawnPoint spawnPoint, Inventory inventory)
{
var skewedChances = ComputeSkewedChances(spawnPoint, inventory);
return SelectItem(skewedChances);
}
private List<(Spawnable Item, double Chance)> ComputeSkewedChances(SpawnPoint spawnPoint, Inventory inventory)
{
return spawnPoint.Items
.Select(pair =>
{
var (item, baseChance) = pair;
var ownedCount = inventory.GetItemCount(item);
var factor = SkewFactor / (ownedCount + SkewFactor);
return (item, baseChance * factor);
})
.ToList();
}
private Spawnable SelectItem(List<(Spawnable Item, double Chance)> probabilities)
{
var chanceSum = probabilities.Sum(item => item.Chance);
var rand = _random.NextDouble() * chanceSum;
var index = 0;
while (rand > probabilities[index].Chance)
{
rand -= probabilities[index].Chance;
index++;
}
return probabilities[index].Item;
}
}
@Broxzier
Copy link
Author

If collecting and not using the spawnabales (as resources), the drop rate essentually flattens out. Making it spawn 10k items starting with none and picking them all, you get these results:

Spawned 56,12% butterflies
Spawned 35,92% bumblebees
Spawned 7,96% cockroaches

As you can see, the rarest item (cockroaches) went up from 1.5% to nearly 8%. In games, players usually use up resources they get, so in practise the rarer drops will still be lower than this, while still skewed in their favour.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment