protected override void OnUpdate() { if (spawned) { return; } spawned = true; // Instead of performing structural changes directly, a Job can add a command to an EntityCommandBuffer to // perform such changes on the main thread after the Job has finished. Command buffers allow you to perform // any, potentially costly, calculations on a worker thread, while queuing up the actual insertions and // deletions for later. var commandBuffer = m_EntityCommandBufferSystem.CreateCommandBuffer().AsParallelWriter(); var poissonsManaged = FastPoissonDiskSampling.Sampling(Vector2.zero, Area, Constants.MinDistanceBetweenAgents).ToArray(); var poissons = new NativeArray <Vector2>(poissonsManaged, Allocator.TempJob); // Schedule the job that will add Instantiate commands to the EntityCommandBuffer. // Since this job only runs on the first frame, we want to ensure Burst compiles it before running to get the best performance (3rd parameter of WithBurst) // The actual job will be cached once it is compiled (it will only get Burst compiled once). var spawnerJob = Entities .WithName("SpawnerSystem") .WithBurst(FloatMode.Default, FloatPrecision.Standard, true) .ForEach((Entity entity, int entityInQueryIndex, ref Spawner spawner, in LocalToWorld location) => { var random = new Random(1); spawner.Area = Vector2.one * Constants.AreaSize * Constants.MinDistanceBetweenAgents; //Debug.Log($"Spawning with infection ratio of {spawner.InitialInfectedRatio}"); //for (var x = 0; x < spawner.CountX; x++) { //for (var y = 0; y < spawner.CountY; y++) for (var i = 0; i < poissons.Length; i++) { var poisson = poissons[i]; var instance = commandBuffer.Instantiate(entityInQueryIndex, spawner.Prefab); // Place the instantiated in a grid with some noise const float dist = 1.7f; //var position = math.transform(location.Value, new float3(x * dist, noise.cnoise(new float2(x, y) * 0.21F) * 2, y * dist)); var position = math.transform(location.Value, new float3(poisson.x, noise.cnoise(new float2(poisson.x, poisson.y) * 0.21F) * 2, poisson.y)); commandBuffer.SetComponent(entityInQueryIndex, instance, new Translation { Value = position }); commandBuffer.SetComponent(entityInQueryIndex, instance, new LifeTime { Value = random.NextFloat(1.0F, 10.0F) }); commandBuffer.SetComponent(entityInQueryIndex, instance, new RotationSpeed { RadiansPerSecond = math.radians(random.NextFloat(25.0F, 90.0F)) }); AgentState state = AgentState.Healthy; var rand = random.NextFloat(); if (rand < spawner.InitialInfectedRatio) { state = AgentState.Infected; } // -2 because game stalls a second when it starts var dt = random.NextFloat() * Constants.TickTime - Constants.TickDelayTime; commandBuffer.SetComponent(entityInQueryIndex, instance, new Agent { State = state, DeltaTime = dt, IsWearingMask = spawner.WearingMask, });; if (state == AgentState.Healthy) { spawner.TotalHealthy++; } else { spawner.TotalInfected++; } } } //commandBuffer.DestroyEntity(entityInQueryIndex, entity); }).ScheduleParallel(Dependency); Dependency = spawnerJob; var disposeJobHandle = poissons.Dispose(Dependency); Dependency = disposeJobHandle; // SpawnJob runs in parallel with no sync point until the barrier system executes. // When the barrier system executes we want to complete the SpawnJob and then play back the commands // (Creating the entities and placing them). We need to tell the barrier system which job it needs to // complete before it can play back the commands. m_EntityCommandBufferSystem.AddJobHandleForProducer(Dependency); }
public override void Generate(bool reallocate) { base.Generate(reallocate); BaseTerrain t = gameObject.GetComponentInParent <BaseTerrain>(); if (!reallocate) { for (int i = 0; i < t.resolution; i++) { for (int j = 0; j < t.resolution; j++) { elevationValues[i, j] = 0; colorValues[i, j] = Color.clear; } } } Random.InitState(seed); List <Vector2> craterPositions; if (poissonSampling) { craterPositions = FastPoissonDiskSampling.Sampling(Vector2.zero, Vector2.one * t.size, t.size / Mathf.Sqrt(craters)); } else { craterPositions = new List <Vector2>((int)craters); for (int i = 0; i < craters; i++) { craterPositions.Add(new Vector2(Random.value, Random.value) * t.size); } } FastNoiseSIMD shapeNoise = new FastNoiseSIMD(seed); shapeNoise.SetNoiseType(FastNoiseSIMD.NoiseType.Perlin); float[] shapeNoiseSet = shapeNoise.GetNoiseSet(0, 0, 0, t.resolution, 1, t.resolution, t.size / t.resolution / shapeNoiseScale); float[] rcNoiseSet = ridgeColorNoise.fastNoiseSIMD.GetNoiseSet(0, 0, 0, t.resolution, 1, t.resolution, t.size / t.resolution); float[] hcNoiseSet = holeColorNoise.fastNoiseSIMD.GetNoiseSet(0, 0, 0, t.resolution, 1, t.resolution, t.size / t.resolution); foreach (Vector2 craterPos in craterPositions) { float variation = 0; if (enableVariation) { variation = Mathf.Pow(Random.Range(0f, 1f), Mathf.Exp(-variationShapeFactor / 5)) * 2 - 1; } float r = Tools.Variate(radius, variation); float hd = Tools.Variate(holeDepth, variation); float hs = Tools.Variate(holeSteepness, variation); float rh = Tools.Variate(rimHeight, variation); float rs = Tools.Variate(rimSteepness, variation); float sf = Tools.Variate(smoothFactor, variation); float rcv = Tools.Variate(ridgeColorValue, variation); float rca = Tools.Variate(ridgeColorAlpha, variation); float rcspr = Tools.Variate(ridgeColorSpread, variation); float rcdc = Tools.Variate(ridgeColorDecay, variation); float rcnstr = Tools.Variate(ridgeColorNoiseStrength, variation); float hcv = Tools.Variate(holeColorValue, variation); float hca = Tools.Variate(holeColorAlpha, variation); float hcds = Tools.Variate(holeColorDropSteepness, variation); float hcnstr = Tools.Variate(holeColorNoiseStrength, variation); float elevationRadius = r + Mathf.Sqrt(rh / rs); float colorRadius = r + rcspr; float affectedRadius = Mathf.Max(elevationRadius, colorRadius); int minx = Math.Max(0, Mathf.FloorToInt((craterPos.x - affectedRadius) / t.size * t.resolution)); int miny = Math.Max(0, Mathf.FloorToInt((craterPos.y - affectedRadius) / t.size * t.resolution)); int maxx = Math.Min(t.resolution, Mathf.CeilToInt((craterPos.x + affectedRadius) / t.size * t.resolution)); int maxy = Math.Min(t.resolution, Mathf.CeilToInt((craterPos.y + affectedRadius) / t.size * t.resolution)); MouseIndicator mi = gameObject.GetComponentInParent <BaseTerrain>().GetComponentInChildren <MouseIndicator>(); for (int x = minx; x < maxx; x++) { for (int y = miny; y < maxy; y++) { float dist = (new Vector2(x, y) / t.resolution * t.size - craterPos).magnitude + shapeNoiseSet[x + t.resolution * y] * shapeNoiseStrength; // Adapted from S. Lague - https://github.com/SebLague/Solar-System float hole = (Tools.Square(dist / r) - 1) * (hd + rh) * hs + rh; float rimX = Mathf.Min(dist - elevationRadius, 0); float rim = rs * Tools.Square(rimX); float craterShape = Tools.SmoothMax(hole, -hd, sf); craterShape = Tools.SmoothMin(craterShape, rim, sf); elevationValues[x, y] += craterShape; float distToRidge = Mathf.Abs(dist - r); Color ridgeColor = new Color(rcv, rcv, rcv, rca); ridgeColor.a += rcNoiseSet[x + t.resolution * y] * rcnstr; ridgeColor.a *= Mathf.Pow(Mathf.Max(0, 1 - distToRidge / rcspr), rcdc); Color holeColor = new Color(hcv, hcv, hcv, hca); holeColor.a += hcNoiseSet[x + t.resolution * y] * hcnstr; holeColor.a *= Mathf.Max(0, Tools.SmoothMin(hcds * (1 - dist / r), 1, .5f)); colorValues[x, y] = Tools.OverlayColors(colorValues[x, y], holeColor); colorValues[x, y] = Tools.OverlayColors(colorValues[x, y], ridgeColor); } } } }