Last active
February 11, 2024 10:23
-
-
Save shun126/858a772178768e7075fd648e5863ff71 to your computer and use it in GitHub Desktop.
Unreal Engine用確率指定可能な抽選関数
This file contains 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
/* | |
Unreal Engine用 | |
確率付き抽選に関するヘッダーファイル | |
https://www.youtube.com/channel/UCkLXe57GpUyaOoj2ycREU1Q | |
*/ | |
#pragma once | |
#include <Kismet/BlueprintFunctionLibrary.h> | |
#include "DrawLots.generated.h" | |
/* | |
当選確率と当選アイテム | |
*/ | |
USTRUCT(BlueprintType) | |
struct FLotteryItem | |
{ | |
GENERATED_BODY() | |
// 抽選確率 | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ClampMin = "1")) | |
uint8 Odds = 1; | |
// 当選アイテム | |
UPROPERTY(EditAnywhere, BlueprintReadWrite) | |
TObjectPtr<UObject> Item; | |
// コンストラクタ | |
FLotteryItem() | |
: Odds(1) | |
, Item(nullptr) | |
{} | |
// コンストラクタ | |
FLotteryItem(const uint8 odds, UObject* item) noexcept | |
: Odds(odds) | |
, Item(item) | |
{} | |
}; | |
/* | |
当選確率が指定可能な抽選データ | |
LotteryItemsに抽選したいFLotteryItemを追加してDrawLotsObject関数を呼ぶと抽選します | |
*/ | |
USTRUCT(BlueprintType) | |
struct FDrawLotsObject | |
{ | |
GENERATED_BODY() | |
// 抽選アイテム | |
UPROPERTY(EditAnywhere, BlueprintReadWrite) | |
TArray<FLotteryItem> LotteryItems; | |
// 抽選 | |
UObject* Draw(const bool consecutive) const | |
{ | |
TArray<FLotteryItem> items; | |
items.Reserve(LotteryItems.Num()); | |
int32 totalWeight = 0; | |
for (int32 i = 0; i < LotteryItems.Num(); ++i) | |
{ | |
if (consecutive || i != mLastLotteryNumber) | |
{ | |
const auto& lotteryItem = LotteryItems[i]; | |
totalWeight += lotteryItem.Odds; | |
items.Emplace(totalWeight, lotteryItem.Item); | |
} | |
} | |
if (totalWeight <= 0) | |
return nullptr; | |
// TODO: specify random numbers externally. | |
const int32 rnd = FGenericPlatformMath::Rand() % totalWeight; | |
for (int32 i = 0; i < items.Num(); ++i) | |
{ | |
const auto& item = items[i]; | |
if (rnd < item.Odds) | |
{ | |
mLastLotteryNumber = i; | |
return item.Item; | |
} | |
} | |
return nullptr; | |
} | |
private: | |
mutable int32 mLastLotteryNumber = -1; | |
}; | |
/* | |
当選確率が指定可能な抽選データ | |
Oddsに確率を定義してDrawLotsIndex関数を呼ぶと抽選します | |
*/ | |
USTRUCT(BlueprintType) | |
struct FDrawLotsIndex | |
{ | |
GENERATED_BODY() | |
// 確率(1以上の値を入力してください) | |
UPROPERTY(EditAnywhere, BlueprintReadWrite) | |
TArray<uint8> Odds; | |
// 抽選 | |
int32 Draw(const bool consecutive) const | |
{ | |
TArray<int32> items; | |
items.Reserve(Odds.Num()); | |
int32 totalWeight = 0; | |
for (int32 i = 0; i < Odds.Num(); ++i) | |
{ | |
if (consecutive || i != mLastLotteryNumber) | |
{ | |
totalWeight += Odds[i]; | |
items.Add(totalWeight); | |
} | |
} | |
if (totalWeight <= 0) | |
return -1; | |
// TODO: specify random numbers externally. | |
const int32 rnd = FGenericPlatformMath::Rand() % totalWeight; | |
for (int32 i = 0; i < items.Num(); ++i) | |
{ | |
if (rnd < items[i]) | |
{ | |
mLastLotteryNumber = i; | |
return i; | |
} | |
} | |
return -1; | |
} | |
private: | |
mutable int32 mLastLotteryNumber = -1; | |
}; | |
/* | |
確率指定可能な抽選関数 | |
*/ | |
UCLASS(Blueprintable) | |
class UDrawLotsBlueprint : public UBlueprintFunctionLibrary | |
{ | |
GENERATED_BODY() | |
public: | |
/* | |
当選確率が指定可能な抽選 | |
当選したアイテムを返します。 | |
確率をすべて0にした場合など抽選できない場合はnullptrを返します。 | |
consecutiveを無効にすると同じアイテムが連続で当選しません | |
*/ | |
UFUNCTION(BlueprintCallable) | |
static UObject* DrawLotsObject(const FDrawLotsObject& drawLotsObject, const bool consecutive = true) | |
{ | |
return drawLotsObject.Draw(consecutive); | |
} | |
/* | |
当選確率が指定可能な抽選をします | |
当選した配列番号を返します。 | |
確率をすべて0にした場合など抽選できない場合は-1を返します。 | |
consecutiveを無効にすると同じ番号が連続で当選しません | |
*/ | |
UFUNCTION(BlueprintCallable) | |
static int32 DrawLotsIndex(const FDrawLotsIndex& drawLotsIndex, const bool consecutive = true) | |
{ | |
return drawLotsIndex.Draw(consecutive); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment