Issues generating random within a Job

Hello all,

I’ve researched this quite a bit and found a solution that, I think, works. However, the results aren’t quite what I expected and I’d love some helpful eyes to see if others might spot the error.

My code aims to spawn enemies based on the position of a “Spawner” (LeftSpawner) and then adds variance in the position based on the Y scale of said object.

   private void SpawnInitialEnemies()
    {
        EntityCommandBuffer.Concurrent commandBuffer = beginInitializationEntityCommandBufferSystem.CreateCommandBuffer().ToConcurrent();

        Entities
            .ForEach((Entity entity, int entityInQueryIndex, in DirectionalEnemyData directionalEnemyData, in LevelData levelData) =>
        {
            // Perhaps a more efficient way to get components of a single Entity that you have a reference too?
            ComponentDataFromEntity<Translation> allTranslations = GetComponentDataFromEntity<Translation>(true);
            ComponentDataFromEntity<CompositeScale> allScales = GetComponentDataFromEntity<CompositeScale>(true);

            if (!allTranslations.Exists(levelData.LeftSpawner) || !allScales.Exists(levelData.LeftSpawner))
            {
                return;
            }

            // Get position of Spawner and Y Scale for later manipulation
            Translation initialSpawnPos = allTranslations[levelData.LeftSpawner];
            float zVariance = allScales[levelData.LeftSpawner].Value.c2.z / 2;

            uint BaseSeed = 1;

            for (int i = 0; i < levelData.InitialAmountOfEnemies; i++)
            {
                // Spawn enemies
                Entity enemyInstance = commandBuffer.Instantiate(entityInQueryIndex, directionalEnemyData.DirectionalEnemyPrefab);

                uint seed = (uint)(BaseSeed + entityInQueryIndex + i);
                Random random = new Random(seed);
                zVariance = random.NextFloat(-zVariance, zVariance);

                commandBuffer.SetComponent(entityInQueryIndex, enemyInstance, new Translation { Value = initialSpawnPos.Value + new float3(0, 0, zVariance) });
            }

        }).ScheduleParallel();

        beginInitializationEntityCommandBufferSystem.AddJobHandleForProducer(Dependency);
    }

Now this bit:

uint seed = (uint)(BaseSeed + entityInQueryIndex + i);
Random random = new Random(seed);
zVariance = random.NextFloat(-zVariance, zVariance);

Does the randomness, however, the result is always either very close to the max or very close to the minimal value.

I’m used to using Unity’s built in Random.Range so using seeds and whatnot is a little new to me.

Thank you in advance,
Ramses

Try using “CreateFromIndex”. It uses a special hashing function to make sure that random seeds initiated sequentially in a loop like that are sufficiently different from one another.

Another thing to try is to get rid of recalculating the seed in the inner loop and instead use a single lambda-captured Random. Then use Schedule instead of ScheduleParallel. If that gives you a better distribution, then you may want to consider not doing RNG in parallel (I’m personally rarely satisfied with the results).

You should be using seed either before job, or at initialization (start), when possible.
Then knowing number of entities, you can pre-generate all random values that you need. Then you pass result into your job.

I am finding however, that getting first random after setting seed, gives undesired result. Every next value is more correct.

You can set seed before FOR loop in line 23, and then just use random values inside the FOR loop.

Alternatively add another FOR loop before line 23, to generate random values, from the seed, Mind putting seed before fore loop.

Thank you all!

@Antypodish was right, I need to define the random BEFORE the loop and then call random.NextFloat every loop to get proper randomness, rather than redefining it every single loop.