Hi, posting here for the first time.
I have a problem with FRandomStream. What I do is create said stream in my .h file.
FRandomStream Stream;
Then, I initialize it in the constructor with my seed.
Stream.Initialize(Seed);
Now, to simplify things, I have a function ‘a’ that calls function ‘b’ a few times. They both belong to this class with the FRandomStream. Function ‘b’ starts “while(true)” loop and it’s supposed to generate random numbers using “Stream” until it gets the number that passes the check.
int32 randNum;
while (true)
{
randNum = Stream.RandRange(0, 5);
if (randNum > 3)
{
return;
}
}
The problem is that when the number that doesn’t pass the check is generated, the next pass of the loop generates the exact same number and I’m getting stuck in while(true) loop forever.
are you really sure, that you do not initialize the stream with the same seed over and over when starting the loop? Typically you will ony set a seed ONCE, then the stream produces random outputs. When initializing the stream again with the same seed, the same number gets created again.
And instead of using an FRandomStream, what about using simply the bultin functions in FMath to make things even simpler:
Hi, thanks for the reply!
I’m 100% positive I only initialize the stream once. In the while loop I call “RandRange” on it and that’s it. The reason I use FRandomStream is because I want my game to produce same results if I use the same seed.
Any other ideas what could be wrong? Thanks again!
I did and that revealed to me that I was actually initializing my stream with 0 every time while doing it in constructor. The stream initializes correctly when doing it in BeginPlay, however the problem remains and while in loop, if the check is not passed the value from there on is the same and it gets stuck forever.
Your code is fine I tested it, the only problem that could cause this is like herb64 mentioned, the Stream is being initialized again or a new Stream is used with the same seed.
I just tested it too and it works as intended, it returns different values, and there are no issues with the while loop. I initialized it on BeginPlay() once.
Just checked the entire class tho and swear to God I only initialize this once and then call RandRange a few times on it. There might be something I missed tho… will do some further testing once I’m back from work.
I did some more testing again, and found no way to produce your effect except for initializing the stream again. Also, I was curious how this is done in the engine source, but at least I could not find anything in RandomStream.h that would explain your effect.
Sorry for the late reply, just go back from work. Here’s the actuall code, where I’m gettin stuck.
while (true)
{
bcanProceed = true;
randomSpotAlongWall = Stream.RandRange(Rooms[randomRoomID].TopX - 2, Rooms[randomRoomID].BottomX + 2);
UE_LOG(LogTemp, Warning, TEXT("In \"while(true)\" loop! (random
spot: %i)"), randomSpotAlongWall);
if (doorStart > -1)
{
if (randomSpotAlongWall <= doorStart + 1 &&
randomSpotAlongWall >= doorFinish - 1)
{
UE_LOG(LogTemp, Warning, TEXT("Door check
failed!"));
continue;
}
}
//Some more code here if the check passess...
}
After hitting a play button and then shutting unreal down I get this printed inside of visual studio, over and over again, hundreds of times:
-“In “while(true)” loop! (random spot: 108)”
-“Door check failed!”
Checked again and I only initialize FRandomStream once in BeginPlay. One more thing, when I change the seed the program freezes during another check in the same function. Will do some more testing tomorrow as it is pretty late right now. Thanks again for all the inputs!
I found what was wrong… and I feel really dumb now! After half hour of testing I noticed that I passed the parameters into RandRange in wrong order! Change the order so the first parameter is actually smaller then the second one and now it’s working. Thanks for everyone’s input!
Cool, that you did solve this. In your example you actually used 0 and 5 correctly… but doing it in the other way, checking in RandomStream.h explains that.
Calling RandRange(5, 0)
/**
* Helper function for rand implementations.
*
* @return A random number >= Min and <= Max
*/
FORCEINLINE int32 RandRange( int32 Min, int32 Max ) const
{
const int32 Range = (Max - Min) + 1;
return Min + RandHelper(Range);
}
Range is now -4 and passed to Randhelper.
FORCEINLINE int32 RandHelper( int32 A ) const
{
// GetFraction guarantees a result in the [0,1) range.
return ((A > 0) ? FMath::TruncToInt(GetFraction() * float(A)) : 0);
}
RandHelper checks for > 0 and now returns 0, always!
And this makes RandRange return 5+0 - > always !!
Maybe Epic could add some checks for negative values as well and handle that with an ensure assertion instead of just returning 0 in RandHelper.