Created
November 30, 2025 04:51
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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