Skip to content

Instantly share code, notes, and snippets.

@LuviKunG
Created November 30, 2025 04:51
Show Gist options
  • Select an option

  • Save LuviKunG/1896a517634672aa99c14db7c3985cf2 to your computer and use it in GitHub Desktop.

Select an option

Save LuviKunG/1896a517634672aa99c14db7c3985cf2 to your computer and use it in GitHub Desktop.
Unreal Engine 5 C++ scripts for add items with assigning weight to pick randomly.
// Made by Thanut Panichyotai (@LuviKunG)
// https://luvikung.github.io
// Attribution 4.0 International CC BY 4.0 Deed
// https://creativecommons.org/licenses/by/4.0/deed.en
#pragma once
#include "CoreMinimal.h"
#include "UObject/GCObject.h"
#include "Containers/Map.h"
/**
* Generic weight-based random selection class for Unreal Engine 5
* Allows adding items with weights and randomly selecting them based on weight distribution
*/
template <typename T>
class UNGRAVITY_API TWeight : public FGCObject
{
public:
/**
* Default Constructor
*/
TWeight() :
TotalWeight(0.0f)
{
}
/** Destructor */
virtual ~TWeight() override
{
WeightMap.Reset();
}
/**
* Add an item with specified weight
* @param Item - The item to add
* @param Weight - The weight of the item (must be > 0)
* @return true if added successfully, false if item already exists or weight is invalid
*/
bool Add(const T& Item, float Weight)
{
if (Weight <= 0.0f)
{
return false;
}
if (WeightMap.Contains(Item))
{
WeightMap[Item] += Weight;
}
else
{
WeightMap.Add(Item, Weight);
}
RecalculateWeights();
return true;
}
/**
* Remove an item from the weight collection
* @param Item - The item to remove
* @return true if removed successfully, false if item doesn't exist
*/
bool Remove(const T& Item)
{
if (!WeightMap.Contains(Item))
{
return false;
}
WeightMap.Remove(Item);
RecalculateWeights();
return true;
}
/**
* Clear all items and cache
*/
void Clear()
{
WeightMap.Empty();
TotalWeight = 0.0f;
}
/**
* Get the weight of a specific item
* @param Item - The item to get weight for
* @return The weight of the item, or -1.0f if not found
*/
float GetWeight(const T& Item) const
{
if (const float* Weight = WeightMap.Find(Item))
{
return *Weight;
}
return -1.0f;
}
/**
* Get the total weight of all items
* @return Total weight
*/
float GetTotalWeight() const
{
return TotalWeight;
}
/**
* Set the weight of a specific item
* @param Item - The item to update
* @param NewWeight - The new weight (must be > 0)
* @return true if updated successfully, false if item doesn't exist or weight is invalid
*/
bool Set(const T& Item, float NewWeight)
{
if (NewWeight <= 0.0f)
{
return false;
}
if (WeightMap.Contains(Item))
{
WeightMap[Item] = NewWeight;
}
else
{
WeightMap.Add(Item, NewWeight);
}
RecalculateWeights();
return true;
}
/**
* Recalculate weight ranges for all items
* This normalizes weights to 0.0-1.0 range for picking
*/
void RecalculateWeights()
{
TotalWeight = 0.0f;
// Calculate total weight
for (const auto& Pair : WeightMap)
{
TotalWeight += Pair.Value;
}
}
/**
* Pick a random item based on weights
* @param Weight Get the item
* @return Pointer to the selected item, or nullptr if no items exist
*/
const T* Pick(const float Weight) const
{
if (WeightMap.Num() == 0)
{
return nullptr;
}
float CumulativeWeight = 0.0f;
for (const TPair<T, float>& Pair : WeightMap)
{
CumulativeWeight += Pair.Value;
if (Weight <= CumulativeWeight)
{
return &Pair.Key;
}
}
return nullptr;
}
/**
* Pick a random item based on weights
* @return Pointer to the selected item, or nullptr if no items exist
*/
const T* PickRandom() const
{
const float RandomWeight = FMath::FRandRange(0.0f, TotalWeight);
return Pick(RandomWeight);
}
/**
* Get the number of items in the collection
*/
int32 Num() const
{
return WeightMap.Num();
}
/**
* Check if the collection is empty
*/
bool IsEmpty() const
{
return WeightMap.Num() == 0;
}
/**
* Check if an item exists in the collection
*/
bool Contains(const T& Item) const
{
return WeightMap.Contains(Item);
}
/**
* Get all items in the collection
*/
void GetAllItems(TArray<T>& OutItems) const
{
WeightMap.GetKeys(OutItems);
}
#pragma region FGCObject interface
virtual void AddReferencedObjects(FReferenceCollector& Collector) override
{
// Add references for DataType if it's a UObject-derived type
// This is automatically handled by TMap for UObject pointers
}
virtual FString GetReferencerName() const override
{
return TEXT("TWeight");
}
#pragma endregion
private:
/**
* Map storing items and their weights
*/
TMap<T, float> WeightMap;
/**
* Total weight of all items
*/
float TotalWeight;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment