protected override JobHandle OnUpdate(JobHandle inputDeps) { var settings = ECSController.FlockParams; var gameSettings = GlobalSettings.Instance; EntityManager.GetAllUniqueSharedComponentData(UniqueTypes); int targetsCount = BoidTargetsGroup.CalculateLength(); int obstaclesCount = BoidObstaclesGroup.CalculateLength(); UIControl.Instance.NrOfObstacles = obstaclesCount; // Ignore typeIndex 0, can't use the default for anything meaningful. for (int typeIndex = 1; typeIndex < UniqueTypes.Count; typeIndex++) { Boid boid = UniqueTypes[typeIndex]; BoidGroup.SetFilter(boid); var boidCount = BoidGroup.CalculateLength(); UIControl.Instance.NrOfBoidsAlive = boidCount; var cacheIndex = typeIndex - 1; // containers that store all the data. var cellIndices = new NativeArray <int>(boidCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var hashMap = new NativeMultiHashMap <int, int>(boidCount, Allocator.TempJob); var cellCount = new NativeArray <int>(boidCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var cellAlignment = new NativeArray <float3>(boidCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var cellPositions = new NativeArray <float3>(boidCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var targetsPositions = new NativeArray <float3>(targetsCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var closestTargetIndices = new NativeArray <int>(boidCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var obstaclesPositions = new NativeArray <float3>(obstaclesCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var closestObstacleIndices = new NativeArray <int>(boidCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var closestObstacleSqDistances = new NativeArray <float>(boidCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); float3 sumOfAllBoidsPositions = float3.zero; // copy values to buffers. var initialCellAlignmentJob = new CopyHeadingsInBuffer { headingsResult = cellAlignment }; var initialCellAlignmentJobHandle = initialCellAlignmentJob.Schedule(BoidGroup, inputDeps); var initialCopyPositionJob = new CopyPositionsInBuffer { positionsResult = cellPositions }; var initialCopyPositionJobHandle = initialCopyPositionJob.Schedule(BoidGroup, inputDeps); var sumPositionsJob = new SumPositions { positionsSum = sumOfAllBoidsPositions }; var sumPositionsJobHandle = sumPositionsJob.Schedule(BoidGroup, inputDeps); // copy targets positions var copyPositionsOfTargetsJob = new CopyPositionsInBuffer { positionsResult = targetsPositions }; var copyPositionsOfTargetsJobHandle = copyPositionsOfTargetsJob.Schedule(BoidTargetsGroup, inputDeps); // copy obstacles positions var copyPositionsOfObstaclesJob = new CopyPositionsInBuffer { positionsResult = obstaclesPositions }; var copyPositionsOfObstaclesJobHandle = copyPositionsOfObstaclesJob.Schedule(BoidObstaclesGroup, inputDeps); var newCellData = new CellsData { indicesOfCells = cellIndices, hashMapBlockIndexWithBoidsIndex = hashMap, sumOfDirectionsOnCells = cellAlignment, sumOfPositionsOnCells = cellPositions, nrOfBoidsOnCells = cellCount, targetsPositions = targetsPositions, closestTargetIndices = closestTargetIndices, closestObstacleIndices = closestObstacleIndices, closestObstacleSqDistances = closestObstacleSqDistances, obstaclesPositions = obstaclesPositions, }; if (cacheIndex > (_CellsData.Count - 1)) { _CellsData.Add(newCellData); } else { DisposeCellData(_CellsData[cacheIndex]); } _CellsData[cacheIndex] = newCellData; // hash the entity position var hashPositionsJob = new HashPositionsToHashMap { hashMap = hashMap.ToConcurrent(), cellRadius = ECSController.Instance.CellSizeVaried, positionOffsetVary = ECSController.Instance.PositionNeighbourCubeOffset }; var hashPositionsJobHandle = hashPositionsJob.Schedule(BoidGroup, inputDeps); // set all cell count to 1. var initialCellCountJob = new MemsetNativeArray <int> { Source = cellCount, Value = 1 }; var initialCellCountJobHandle = initialCellCountJob.Schedule(boidCount, 64, inputDeps); // bariers. from now on we need to use the created buffers. // and we need to know that they are finished. var initialCellBarrierJobHandle = JobHandle.CombineDependencies( initialCellAlignmentJobHandle, initialCopyPositionJobHandle, initialCellCountJobHandle); var mergeCellsBarrierJobHandle = JobHandle.CombineDependencies( hashPositionsJobHandle, initialCellBarrierJobHandle, sumPositionsJobHandle); var targetsJobHandle = JobHandle.CombineDependencies(mergeCellsBarrierJobHandle, copyPositionsOfTargetsJobHandle, copyPositionsOfObstaclesJobHandle); var mergeCellsJob = new MergeCellsJob { indicesOfCells = cellIndices, cellAlignment = cellAlignment, cellPositions = cellPositions, cellCount = cellCount, targetsPositions = targetsPositions, closestTargetIndexToCells = closestTargetIndices, closestObstacleSqDistanceToCells = closestObstacleSqDistances, closestObstacleIndexToCells = closestObstacleIndices, obstaclesPositions = obstaclesPositions }; // job now depends on last barrier. var mergeCellsJobHandle = mergeCellsJob.Schedule(hashMap, 64, targetsJobHandle); EntityCommandBuffer.Concurrent commandBuffer = barrierCommand.CreateCommandBuffer().ToConcurrent(); NativeQueue <float3> killedPositionsQueue = new NativeQueue <float3>(Allocator.TempJob); var steerJob = new MoveBoids { cellIndices = newCellData.indicesOfCells, alignmentWeight = gameSettings.AlignmentWeight, separationWeight = gameSettings.SeparationWeight, cohesionWeight = gameSettings.CohesionWeight, cellSize = ECSController.Instance.CellSizeVaried, sphereBoundarySize = gameSettings.SphereBoundarySize, sphereBoundaryWeight = gameSettings.BoundaryWeight, moveSpeed = gameSettings.MoveSpeed, cellAlignment = cellAlignment, cellPositions = cellPositions, cellCount = cellCount, dt = Time.deltaTime, walkToFlockCenterWeight = gameSettings.WalkToFlockCenterWeight, sumOfAllPositions = sumOfAllBoidsPositions, nrOfTotalBoids = boidCount, maintainYWeight = gameSettings.maintainYWeight, yLength = gameSettings.yLength, perlinNoiseScale = settings.perlinNoiseScale, targetsPositions = targetsPositions, cellClosestTargetsIndices = closestTargetIndices, goToTargetsWeight = gameSettings.goToTargetsWeight, obstaclesPositions = obstaclesPositions, cellClosestObstaclesIndices = closestObstacleIndices, cellClosestObstaclesSqDistances = closestObstacleSqDistances, startAvoidingObstacleAtDistance = gameSettings.avoidDistanceObstacles, avoidObstaclesWeight = gameSettings.avoidObstaclesWeight, terrainY = ECSController.TerrainY, distanceToAvoidTerrain = settings.distanceToAvoidTerrain, avoidTerrainWeight = gameSettings.avoidTerrainWeight, avoidXZwhileHeightBiggerThan = settings.avoidXZwhileHeightBiggerThan, avoidXZwhileHeightBiggerFade = settings.avoidXZwhileHeightBiggerFade, obstacleKillRadius = settings.obstacleKillRadius, commandBuffer = commandBuffer, diedPositions = killedPositionsQueue.ToConcurrent(), }; // job depends on merge cells job var steerJobHandle = steerJob.Schedule(BoidGroup, mergeCellsJobHandle); barrierCommand.AddJobHandleForProducer(steerJobHandle); steerJobHandle.Complete(); if (killedPositionsQueue.TryDequeue(out float3 pos)) { GameController.Instance.KilledBoidAt(pos); } killedPositionsQueue.Dispose(); inputDeps = steerJobHandle; BoidGroup.AddDependency(inputDeps); } UniqueTypes.Clear(); return(inputDeps); }
protected override JobHandle OnUpdate(JobHandle inputDeps) { if (!controller) { controller = BoidControllerECSJobsFast.Instance; } if (controller) { int boidCount = boidGroup.CalculateEntityCount(); var cellIndices = new NativeArray <int>(boidCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var cellBoidCount = new NativeArray <int>(boidCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var boidPositions = new NativeArray <float3>(boidCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var boidHeadings = new NativeArray <float3>(boidCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var hashMap = new NativeMultiHashMap <int, int>(boidCount, Allocator.TempJob); var positionsAndHeadingsCopyJob = new CopyPositionsAndHeadingsInBuffer { boidPositions = boidPositions, boidHeadings = boidHeadings }; JobHandle positionsAndHeadingsCopyJobHandle = positionsAndHeadingsCopyJob.Schedule(boidGroup, inputDeps); quaternion randomHashRotation = quaternion.Euler( UnityEngine.Random.Range(-360f, 360f), UnityEngine.Random.Range(-360f, 360f), UnityEngine.Random.Range(-360f, 360f) ); float offsetRange = controller.boidPerceptionRadius / 2f; float3 randomHashOffset = new float3( UnityEngine.Random.Range(-offsetRange, offsetRange), UnityEngine.Random.Range(-offsetRange, offsetRange), UnityEngine.Random.Range(-offsetRange, offsetRange) ); var hashPositionsJob = new HashPositionsToHashMap { hashMap = hashMap.AsParallelWriter(), cellRotationVary = randomHashRotation, positionOffsetVary = randomHashOffset, cellRadius = controller.boidPerceptionRadius, }; JobHandle hashPositionsJobHandle = hashPositionsJob.Schedule(boidGroup, inputDeps); // Proceed when these two jobs have been completed JobHandle copyAndHashJobHandle = JobHandle.CombineDependencies( positionsAndHeadingsCopyJobHandle, hashPositionsJobHandle ); var mergeCellsJob = new MergeCellsJob { indicesOfCells = cellIndices, cellPositions = boidPositions, cellHeadings = boidHeadings, cellCount = cellBoidCount, }; JobHandle mergeCellsJobHandle = mergeCellsJob.Schedule(hashMap, 64, copyAndHashJobHandle); var moveJob = new MoveBoids { deltaTime = Time.DeltaTime, boidSpeed = controller.boidSpeed, separationWeight = controller.separationWeight, alignmentWeight = controller.alignmentWeight, cohesionWeight = controller.cohesionWeight, cageSize = controller.cageSize, cageAvoidDist = controller.avoidWallsTurnDist, cageAvoidWeight = controller.avoidWallsWeight, cellSize = controller.boidPerceptionRadius, cellIndices = cellIndices, positionSumsOfCells = boidPositions, headingSumsOfCells = boidHeadings, cellBoidCount = cellBoidCount, }; JobHandle moveJobHandle = moveJob.Schedule(boidGroup, mergeCellsJobHandle); moveJobHandle.Complete(); hashMap.Dispose(); inputDeps = moveJobHandle; boidGroup.AddDependency(inputDeps); return(inputDeps); } else { return(inputDeps); } }