Need help with a Random Number Generator in Unity C#

Started by
21 comments, last by Lactose 7 years, 6 months ago
I would just use my own congruential random number generator, which is literally 1 line of code.
Then you can just see what happens, instead of guessing https://en.wikipedia.org/wiki/Linear_congruential_generator
Advertisement

Well I tried seeding with the following code:

//Trying to seed with system time
float timeF = Time.realtimeSinceStartup;
int timeI = (int)timeF;
UnityEngine.Random.InitState(timeI);
and I am still running it during Start() and it has no effect on the results. It is as if the seed is always the same no matter whether I try to seed it or not. I start the game, and move between levels and every level has the same pattern every time.

Time.realtimeSinceStartup will be zero at the start of every playthrough - the hint is in the name.

You want to seed it with real world time, which will be different every time you run the game - something like System.Datetime.UtcNow.Ticks.

Time.realtimeSinceStartup will be zero at the start of every playthrough - the hint is in the name.

You want to seed it with real world time, which will be different every time you run the game - something like System.Datetime.UtcNow.Ticks.

Well the tooltip for Time.realtimeSinceStartup says time in second since game start, should mean since the application was started, not the scene was loaded. Which is its current implementation to my knowledge. I read it very carefully actually. Thank you, I will try that.

So I tried to seed with System.DateTime.UtcNow.Ticks and it does not work. I think I have stumbled onto the problem. I have my spawn chance set to 100. That can't be right. Since n cannot be greater than 100 given the random functions I am using, it should be filling every space in the level with objects. It is not, its only filling about half of them. What is going on? I have figured out that with my current code, if I put 30 or less in for the spawnChance only 1 object spawns. Same place, every time. If I put 31 or higher I get the same 15 spawns in the same places every time. This mystery is driving me nuts! What is wrong with my code? It is not the RNG I think. It's the code structure. Or perhaps both.

It is not, its only filling about half of them.

You have an error in the selection/getting of free positions. You are tagging the game objects as attempted in cases where you shouldn't.

You have 2 calls to NextFreePosition. 1 of the calls is just to check if there is a free position, and the other is actually using that position.

In the first case, the game object should not be tagged as attempted.

I would suggest moving the tagging line to where the game object is actually attempted to spawn (inside the if (freePosition) conditional).

EDIT: That is...


if (freePosition)
{
    childPositionGameObject.tag = "Attempted"; //MOVED TO HERE
    //...other stuff here
}

Transform NextFreePosition()
{
    foreach Transform childPositionGameObject in transform
    {
        if ((childPositionGameObject.childCount == 0) & (!childPositionGameObject.CompareTag("Attempted")))
        {
            //childPositionGameObject.tag = "Attempted"; //REMOVED FROM HERE
            return childPositionGameObject;
        }
    }
    return null;
}

Hello to all my stalkers.

Thank you Lactose! that is definitely helpful, and it was indeed an error. Thank you. Now when I set the spawnchance variable to 100, everything spawns as it should. However, the RNG problem from my last post does persist. 30 and below spawn 1 object, 31 and above spawn all. Same problem as before really. Some other error is being missed. Thanks for your help everyone.


There are 30 spots in the level for objects. I just realized that, I doubt that is a coincidence.

The other big bug in your original code is that you only actually ask for a single random number to assign to 'n'.

The other big bug in your original code is that you only actually ask for a single random number to assign to 'n'.


This, but I'm curious what is in the functions "RandomAngleGen" and "MoveRandomly"? Post the code to those. Those two functions are affected by the random number generator and are responsible for generating the level. What is going on inside them? I suspect that the error, at least in part, might be in one of those functions.

I actually eliminated those functions from the problem already by testing without them. They seem to work well actually. They have their own baked in RNG. They rotate the objects, and also move the objects randomly just a bit to create a more organic nature feel to the levels. Here is the updated code in total:

void Start()
{
ResetTags();
SpawnUntilFull();
RNG();
}
void SpawnUntilFull()
{
Transform freePosition = NextFreePosition();
if (freePosition)
{
freePosition.tag = "Attempted";
MoveRandomly();
RandomAngleGen();
ChooseRandomly();
if (n <= spawnChance)
{
LevelManager.breakableCount += 1;
GameObject destructible = Instantiate(chosenGameObject, (freePosition.position + moved), Quaternion.Euler(0, 0, angle)) as GameObject;
destructible.transform.parent = freePosition;
}
if (NextFreePosition())
{
Invoke("SpawnUntilFull", spawnDelay);
}
}
}
void RNG()
{
float timeF = System.DateTime.UtcNow.Ticks;
int timeI = (int)timeF;
UnityEngine.Random.InitState(timeI);
n = UnityEngine.Random.Range(1, 101);
}
void ChooseRandomly()
{
if (n <= chance30hp) { chosenGameObject = asteroid30hp; }
else if (n <= chance20hp) { chosenGameObject = asteroid20hp; }
else if (n <= chance10hp) { chosenGameObject = asteroid10hp; }
}
void MoveRandomly()
{
float x = UnityEngine.Random.Range(-.4f, .4f);
float y = UnityEngine.Random.Range(-.4f, .4f);
moved = new Vector3(x, y, 0);
}
void RandomAngleGen()
{
angle = UnityEngine.Random.Range(0, 181);
}
Transform NextFreePosition()
{
foreach (Transform childPositionGameObject in transform)
{
if ((childPositionGameObject.childCount == 0) & (!childPositionGameObject.CompareTag("Attempted")))
{
return childPositionGameObject;
}
}
return null;
}
void OnDrawGizmos()
{
Gizmos.DrawWireCube(transform.position, new Vector3(width, height));
}
void ResetTags()
{
foreach (Transform childPositionGameObject in transform)
{
childPositionGameObject.tag = "Untagged";
}
}
}
I created the RNG() function and only called it once because after my initial research that was something people mentioned as potentially causing the problem. Should I build in a fresh call in every loop of the main function?

This topic is closed to new replies.

Advertisement