I am trying to translate this working BP script to C++.
Translation
RandomItemType(ItemType); //Randomize items by type
if (ItemsTypeArr.Find(ItemType) == -1) //check for duplicates
{
ItemsTypeArr.Add(ItemType); // add all items to array if not duplicated
}
else if (ItemsTypeArr.Find(ItemType) != -1)//check for duplicates
{
RandomItemType(ItemType);//Re-randomize items to avoid any duplicate
}
the goal is I have 20 groups of items, and the item should not be duplicated in its own group randomly.
the problem is executing this statement logs Array is out of range but in blueprints working fine.
Please correct me if I am not doing the logic correctly, thanks
You can use something like this, I used ECollisionChannel as my enum example
Be careful with this though because you might end up with an infinite loop, check first if your array can still take extra values otherwise the loop with always fail because the array is already filled with all possible options.
ECollisionChannel ItemType;
do
{
ItemType = RandomItemType();
}while(ItemsTypeArr.Contains(ItemType));
ItemsTypeArr.Add(ItemType); //Add the item
2 Likes
Imo the out of range error might be from RandomItemType(ItemType);
.
1 Like
Thank you for reply, RandomItemType()
is a return type function and returning the EItemType
and I need an extra local variable for it?
You need to store the returned value , if you call it again it will get you a new random type.
1 Like
yep , I am doing something wrong in this function itself , and I now believe that if statement has nothing to do with it… I will update the thread once I figure out the place of the bug
Ok, Thank you for pointing this out
1 Like
got engine crash on clicking play button, but the code compiles fine in VS
Can you show your RandomItemType() function ?
1 Like
void AMyGameMode::RandomItemType(EItemType& ItemType)
{
TArray<EItemType> Arr{};
TArray<FName> OutRowNames{};
if (const UDataTable* DT_ItemTypeProbability = LoadObject<UDataTable>(NULL, TEXT("/Game/DataTables/DT_ItemTypeProbability")))
{
OutRowNames = DT_ItemTypeProbability->GetRowNames();
for (auto& Array : OutRowNames)
{
if (const UDataTable* DT_ItemTypeProbability{ LoadObject<UDataTable>(GetWorld(), TEXT("/Game/DataTables/DT_ItemTypeProbability")) })
{
if (const FST_ItemTypeProbability * OutRow{ DT_ItemTypeProbability->FindRow<FST_ItemTypeProbability>(FName(Array), "") })
{
if (OutRow)
{
TypeProbabilityDatas = *OutRow;
for (int32 i = 1; i < TypeProbabilityDatas.Percent; i++)
{
Arr.Add(TypeProbabilityDatas.Type);
}
}
}
}
}
FCustomThunkTemplates::Array_Shuffle(Arr);
ItemType = Arr[FMath::RandRange(0, 99)];
}
}
bp version in case if you want to see it visually
I see the random integer from 0 to 99 however you can’t guarantee that the array has a valid index, for this I would suggest doing something like to ensure the index is valid:
ItemType = Arr[FMath::RandRange(0, Arr.Num() - 1)];
This will limit the random integer to within range and should fix your out of bound issue.
Edit: changed my example to be similar to your Arr array.
1 Like
yes this out of bound issue is gone but crash on beginplay is still here
don’t know what is wrong with my logics
Did you add the Do while example I provided ? it could be that infinite loop I was talking about.
no, I called this function alone and it works fine, when I call it in the main funciton GenerateItems();
the editor crashes
Let’s take a look at GenerateItems(); if you don’t mind.
1 Like
void AMyGameMode::GenerateItems()
{
EItemType LocItemType{};
int32 LocNumbers{};
TArray<FName> OutRowNames{};
TArray<EItemType> ItemsTypeArr{};
(OutRowNames).Reset();
if (UDataTable *DT_SpawnLocationLobby = LoadObject<UDataTable>(NULL, TEXT("/Game/DataTables/DT_ItemGroupSpawnLocationLobby")))
{
OutRowNames = DT_SpawnLocationLobby->GetRowNames();
for (auto& Array : OutRowNames)
{
if (const UDataTable* DT_SpawnLocationLobby{ LoadObject<UDataTable>(GetWorld(), TEXT("/Game/DataTablesDT_ItemGroupSpawnLocationLobby")) })
{
if (const FST_ItemGroupLocation* OutRow{ DT_SpawnLocationLobby->FindRow<FST_ItemGroupLocation>(FName(Array), "") })
{
if (OutRow)
{
FVector Scale = FVector(1.000000, 1.000000, 1.000000);
// SpawnTransform is the location + rotation + scale (absolute) of the spawn
FTransform SpawnTransform = FTransform(GroupLocationDatas.Location);
// SpawnInfo contains the Collision Handling Override
FActorSpawnParameters SpawnInfo;
SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
// Spawn the actor
TSubclassOf<AActor> AItemGroup = AActor::StaticClass();
AActor* ItemGroupRef = GetWorld()->SpawnActor<AActor>(AItemGroup, SpawnTransform, SpawnInfo);
RandomItemNumber(LocNumbers);
for (auto i = 1; i <= LocNumbers; i++);
//Randomizing the item types
RandomItemType(LocItemType); //Randomize items by type
if (ItemsTypeArr.Find(LocItemType) == -1) //check for duplicates
{
ItemsTypeArr.Add(LocItemType); // add all items to array if not duplicated
}
else if (ItemsTypeArr.Find(LocItemType) != -1)//check for duplicates
{
RandomItemType(LocItemType);//Re-randomize items to avoid any duplicate
}
}
}
}
}
}
}
I can show you the blueprint version if you want
Try adding a breakpoint in this function and see what triggers the crash. Does your blueprint work as intended ? share it as well why not.
1 Like
yes the blueprint works fine , and yes I will be debugging the code with breakpoints