public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) { NativeArray <BoxColliderComponentData> boxColliders = chunk.GetNativeArray(BoxColliderType); NativeArray <Rotation> rotations = chunk.GetNativeArray(RotationType); NativeArray <Position> positions = chunk.GetNativeArray(PositionType); NativeArray <Scale> scales = chunk.GetNativeArray(ScaleType); NativeArray <Entity> entities = chunk.GetNativeArray(EntityType); float3 zero = float3.zero; for (int i = 0, length = boxColliders.Length; i < length; ++i) { BoxColliderComponentData box = boxColliders[i]; Position position = positions[i]; Rotation rotation = rotations[i]; Scale scale = scales[i]; BoxcastCommand boxCast = new BoxcastCommand(position.Value + box.Center, box.Size * scale.Value * 0.5f, quaternion.identity, float3.zero, 0, 0); BoxCasts.TryAdd(entities[i], boxCast); } }
/// <inheritdoc/> public void Execute(int index) { NodeTransform nt = nodesTransforms[index]; // start a bit before the node just in case there's an obstacle overlapping a bit Vector3 center = (Vector3)(nt.pos - nt.up * 0.1f); // nodes are squares and we don't plan to change it float halfWidth = NodeHalfSize * boxNodePercentage; Vector3 halfExtents = new Vector3(halfWidth, 0.01f, halfWidth); commands[index] = new BoxcastCommand(center, halfExtents, (Quaternion)nt.GetRotation(), (Vector3)nt.up, maxCharacterHeight, mask); }
/// <inheritdoc/> public void Execute(int index) { NodeTransform nt = nodesTransforms[index]; // start a bit before the node just in case there's an obstacle overlapping a bit Vector3 center = nt.Pos - nt.Up * 0.1f; // nodes are squares and we don't plan to change it float halfWidth = NodeHalfSize * settings.boxNodePercentage; float halfDepth = halfWidth; Vector3 halfExtents = new Vector3(halfWidth, 0.01f, halfDepth); commands[index] = new BoxcastCommand(center, halfExtents, nt.GetRotation(), nt.Up, settings.maxCharacterHeight, settings.mask); }
public void Execute(int index) { var entity = Entities[index]; var position = entityTransaction.GetComponentData <Position>(entity); var rotation = entityTransaction.GetComponentData <Rotation>(entity); var box = entityTransaction.GetComponentData <BoxColliderComponentData>(entity); var collisionLayer = entityTransaction.GetSharedComponentData <CollisionLayerComponentData>(entity); BoxcastCommand boxcast = Boxcasts[index * 3]; var dir = ((position.Value + box.Center) - (float3)boxcast.center); boxcast.orientation = rotation.Value; boxcast.direction = math.normalizesafe(dir); boxcast.distance = math.length(dir); boxcast.layerMask = collisionLayer.Mask1; Boxcasts[index * 3] = boxcast; boxcast.layerMask = collisionLayer.Mask2; Boxcasts[index * 3 + 1] = boxcast; boxcast.layerMask = collisionLayer.Mask3; Boxcasts[index * 3 + 2] = boxcast; }
/// <summary> /// Creates the grid of nodes. /// </summary> public void CreateGrid() { DestroyGrid(); // TODO: Perhaps we might want to snap the extents value when editing the bounding box // in the editor? Bounds scanBounds = scanCollider.bounds; ScanAreaSettings scanSettings = new ScanAreaSettings((float3)scanBounds.center, (float3)scanBounds.extents, walkableMask); int expectedGridDimension = scanSettings.gridDimension; // TODO: Could I use nodesTypes invalid to avoid any kind of computation from them? nodesTransforms = new NativeArray <NodeTransform>(expectedGridDimension, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); nodesTypes = new NativeArray <NodeType>(expectedGridDimension, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); nodesNeighbors = new NativeArray <NodeNeighbor>(expectedGridDimension * NodeNumNeighbors, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); // calculate the initial raycast commands NativeArray <RaycastCommand> mainCommands = new NativeArray <RaycastCommand>(expectedGridDimension, Allocator.TempJob); JobHandle createNodesHandle = new CalculateRaycastCommandsJob { commands = mainCommands, scanSettings = scanSettings, } .ScheduleParallel(expectedGridDimension, 64, default(JobHandle)); // schedule the commands to retrieve the initial hits NativeArray <RaycastHit> nodeHits = new NativeArray <RaycastHit>(expectedGridDimension, Allocator.TempJob); createNodesHandle = RaycastCommand.ScheduleBatch(mainCommands, nodeHits, 32, createNodesHandle); JobHandle.ScheduleBatchedJobs(); // build the nodes using the received hits and the main raycast commands createNodesHandle = new CreateNodesJob { nodesTransforms = nodesTransforms, nodesTypes = nodesTypes, hits = nodeHits, commands = mainCommands, } .ScheduleParallel(expectedGridDimension, 32, createNodesHandle); // calculate the boxcasts to bake obstacles NativeArray <BoxcastCommand> boxcastCommands = new NativeArray <BoxcastCommand>(expectedGridDimension, Allocator.TempJob); JobHandle bakeObstaclesHandle = new CalculateBoxcastCommandsJob { commands = boxcastCommands, nodesTransforms = nodesTransforms, mask = obstacleMask, boxNodePercentage = boxToNodeObstaclePercentage, maxCharacterHeight = maxCharacterHeight, } .ScheduleParallel(expectedGridDimension, 64, createNodesHandle); // schedule the boxcasts to find possible obstacles NativeArray <RaycastHit> obstacleHits = new NativeArray <RaycastHit>(expectedGridDimension, Allocator.TempJob); bakeObstaclesHandle = BoxcastCommand.ScheduleBatch(boxcastCommands, obstacleHits, 32, bakeObstaclesHandle); // prepare the bake obstacles job bakeObstaclesHandle = new BakeObstaclesJob { nodesTypes = nodesTypes, boxcastHits = obstacleHits, } .ScheduleParallel(expectedGridDimension, 128, bakeObstaclesHandle); // now calculate the neighbors JobHandle calculateNeighborsHandle = new CalculateNeighborsJob { neighbors = nodesNeighbors, nodesTransforms = nodesTransforms, scanSettings = scanSettings, maxWalkableHeightWithStep = maxWalkableHeightWithStep, } .ScheduleParallel(expectedGridDimension, 32, createNodesHandle); JobHandle finalHandle = JobHandle.CombineDependencies(calculateNeighborsHandle, bakeObstaclesHandle); JobHandle disposeHandle = JobHandle.CombineDependencies(mainCommands.Dispose(finalHandle), nodeHits.Dispose(finalHandle)); disposeHandle = JobHandle.CombineDependencies(disposeHandle, boxcastCommands.Dispose(finalHandle), obstacleHits.Dispose(finalHandle)); // wait to complete all the scheduled stuff finalHandle.Complete(); gridWidth = scanSettings.gridWidth; gridDepth = scanSettings.gridDepth; isGridCreated = true; OnGridCreation?.Invoke(); Logger.LogFormat("Grid was created with dimension {0}. Width: {1}. Height: {2}.", expectedGridDimension, gridWidth, gridDepth); disposeHandle.Complete(); }
private void AddDistanceSensors(List <CastBatchItem> castBatchItems) { if (castBatchItems.Count == 0) { return; } // Batch'em NativeArray <RaycastHit> results = new NativeArray <RaycastHit>(castBatchItems.Count, Allocator.TempJob); NativeArray <BoxcastCommand> commands = new NativeArray <BoxcastCommand>(castBatchItems.Count, Allocator.TempJob); foreach (CastBatchItem item in castBatchItems) { Vector3 dir = item.Transform.TransformDirection(new Vector3(item.Sensor.Direction.x, 0, item.Sensor.Direction.z)).normalized; Vector3 raySrc = item.Transform.position + (item.Transform.right * item.Sensor.Origin.x) + (item.Transform.forward * item.Sensor.Origin.z) + (item.Transform.up * item.Sensor.Origin.y); Debug.DrawRay(raySrc, dir * item.Sensor.MaxDistance); commands[item.BatchIndex] = new BoxcastCommand(raySrc, item.Sensor.Extents, Quaternion.identity, dir, item.Sensor.MaxDistance); } // Schedule the batch of raycasts var handle = BoxcastCommand.ScheduleBatch(commands, results, 64); // Wait for the batch processing job to complete handle.Complete(); // Update the results for (int i = 0; i < results.Length; ++i) { CastBatchItem item = castBatchItems[i]; RaycastHit hit = results[i]; double relativeDistance = 0; double relativeAggression = 0; double relativeFitness = 0; if (hit.transform != null) { // Distance relativeDistance = 1 - (hit.distance / item.Sensor.MaxDistance); // Relative Stats GameObjectEntity goe = hit.collider.GetComponent <GameObjectEntity>(); if (goe != null) { Stats otherStats = EntityManager.GetComponentData <Stats>(goe.Entity); // Aggression relativeAggression = item.Stats.Aggression != 0 ? Math.Tanh((otherStats.Aggression / item.Stats.Aggression) - 1) : Math.Tanh(otherStats.Aggression); // Fitness if (item.Stats.Tag == otherStats.Tag) { relativeFitness = item.Stats.Fitness != 0 ? Math.Tanh((otherStats.Fitness / item.Stats.Fitness) - 1) : Math.Tanh(otherStats.Fitness); } else { relativeFitness = -1; } } } item.SensorData.Data[item.ResultIndex + 0] = relativeDistance; item.SensorData.Data[item.ResultIndex + 1] = relativeAggression; item.SensorData.Data[item.ResultIndex + 2] = relativeFitness; } // Dispose the buffers results.Dispose(); commands.Dispose(); return; }
protected override JobHandle OnUpdate(JobHandle inputDeps) { PreCollisionSystem preCollisionSystem = World.Active.GetExistingManager <PreCollisionSystem>(); if (preCollisionSystem != null) { var entities = preCollisionSystem.Entities; var boxcasts = preCollisionSystem.Boxcasts; var spherecasts = preCollisionSystem.Spherecasts; var capsulecasts = preCollisionSystem.Capsulecasts; EntityManager.CompleteAllJobs(); if (boxcasts.IsCreated && boxcasts.Length != 0) { var hitBoxCollider = new NativeArray <RaycastHit>(boxcasts.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var transaction = EntityManager.BeginExclusiveEntityTransaction(); var job = new UpdateBoxDistDir { Boxcasts = boxcasts, Entities = entities, entityTransaction = transaction }; var handle = job.Schedule(boxcasts.Length / 3, 32, inputDeps); EntityManager.ExclusiveEntityTransactionDependency = handle; Utils.Utils.ScheduleBatchedJobAndComplete(handle); EntityManager.EndExclusiveEntityTransaction(); handle = BoxcastCommand.ScheduleBatch(boxcasts, hitBoxCollider, 1, default); Utils.Utils.ScheduleBatchedJobAndComplete(handle); InvokeCollisionResponse(entities, hitBoxCollider, 0, boxcasts.Length); hitBoxCollider.Dispose(); } if (spherecasts.IsCreated && spherecasts.Length != 0) { var hitSphereCollider = new NativeArray <RaycastHit>(spherecasts.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var transaction = EntityManager.BeginExclusiveEntityTransaction(); var job = new UpdateSphereDistDir { Spherecasts = spherecasts, Entities = entities, entityTransaction = transaction, StartIndex = boxcasts.Length / 3 }; var handle = job.Schedule(spherecasts.Length / 3, 32, inputDeps); EntityManager.ExclusiveEntityTransactionDependency = handle; Utils.Utils.ScheduleBatchedJobAndComplete(handle); EntityManager.EndExclusiveEntityTransaction(); handle = SpherecastCommand.ScheduleBatch(spherecasts, hitSphereCollider, 1, default); Utils.Utils.ScheduleBatchedJobAndComplete(handle); InvokeCollisionResponse(entities, hitSphereCollider, boxcasts.Length, spherecasts.Length); hitSphereCollider.Dispose(); } if (capsulecasts.IsCreated && capsulecasts.Length != 0) { var hitCapsuleCollider = new NativeArray <RaycastHit>(capsulecasts.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var transaction = EntityManager.BeginExclusiveEntityTransaction(); var job = new UpdateCapsuleDistDir { Capsulecasts = capsulecasts, Entities = entities, entityTransaction = transaction, StartIndex = (boxcasts.Length + spherecasts.Length) / 3 }; var handle = job.Schedule(capsulecasts.Length / 3, 32, inputDeps); EntityManager.ExclusiveEntityTransactionDependency = handle; Utils.Utils.ScheduleBatchedJobAndComplete(handle); EntityManager.EndExclusiveEntityTransaction(); handle = CapsulecastCommand.ScheduleBatch(capsulecasts, hitCapsuleCollider, 1, default); Utils.Utils.ScheduleBatchedJobAndComplete(handle); InvokeCollisionResponse(entities, hitCapsuleCollider, spherecasts.Length, capsulecasts.Length); hitCapsuleCollider.Dispose(); } } return(inputDeps); }
/// <summary> /// Creates the grid of nodes. /// </summary> public void CreateGrid() { DestroyGrid(); // Note: perhaps we might want to snap the extents value when editing the bounding box // in the editor? Bounds scanBounds = scanCollider.bounds; ScanAreaSettings scanSettings = new ScanAreaSettings(scanBounds.center, scanBounds.extents, walkableMask); int gridDimension = scanSettings.dimension; nodesTransforms = new NativeArray <NodeTransform>(gridDimension, Allocator.Persistent); nodesTypes = new NativeArray <NodeType>(gridDimension, Allocator.Persistent); nodesNeighbors = new NativeArray <NodeNeighbor>(gridDimension * NodeNeighbors, Allocator.Persistent); // calculate the raycast commands CalculateRaycastCommandsJob calculateCommandsJob = new CalculateRaycastCommandsJob(scanSettings); JobHandle calculateCommandsHandle = calculateCommandsJob.Schedule(gridDimension, 32); // schedule the raycast commands to retrieve the hits NativeArray <RaycastHit> nodeHits = new NativeArray <RaycastHit>(gridDimension, Allocator.TempJob); JobHandle raycastCommandHandle = RaycastCommand.ScheduleBatch(calculateCommandsJob.commands, nodeHits, 1, calculateCommandsHandle); // build the nodes using the received hits CreateNodesJob createNodesJob = new CreateNodesJob(nodesTransforms, nodesTypes, nodeHits, calculateCommandsJob.commands); JobHandle createNodesHandle = createNodesJob.Schedule(gridDimension, 32, raycastCommandHandle); // calculate the boxcast commands to bake obstacles BakeObstaclesSettings bakeObstaclesSettings = new BakeObstaclesSettings(maxCharacterHeight, boxToNodeObstaclePercentage, obstacleMask); CalculateBoxcastCommandsJob calculateBoxcastCommandsJob = new CalculateBoxcastCommandsJob(bakeObstaclesSettings, nodesTransforms); JobHandle calculateBoxcastHandle = calculateBoxcastCommandsJob.Schedule(gridDimension, 32, createNodesHandle); // schedule the boxcast commands to retrieve the hits NativeArray <RaycastHit> obstacleHits = new NativeArray <RaycastHit>(gridDimension, Allocator.TempJob); JobHandle boxcastCommandHandle = BoxcastCommand.ScheduleBatch(calculateBoxcastCommandsJob.commands, obstacleHits, 1, calculateBoxcastHandle); // prepare the bake obstacles job BakeObstaclesJob bakeObstaclesJob = new BakeObstaclesJob(nodesTypes, obstacleHits); JobHandle bakeObstaclesHandle = bakeObstaclesJob.Schedule(gridDimension, 32, boxcastCommandHandle); // now calculate the neighbors CalculateNeighborsJob calculateNeighborsJob = new CalculateNeighborsJob(nodesNeighbors, nodesTransforms, scanSettings, maxWalkableStep); JobHandle calculateNeighborsHandle = calculateNeighborsJob.Schedule(gridDimension, 32, bakeObstaclesHandle); // schedule disposing the stuff JobHandle disposeHandle = calculateCommandsJob.commands.Dispose(createNodesHandle); disposeHandle = JobHandle.CombineDependencies(disposeHandle, nodeHits.Dispose(createNodesHandle)); disposeHandle = JobHandle.CombineDependencies(disposeHandle, calculateBoxcastCommandsJob.commands.Dispose(boxcastCommandHandle)); disposeHandle = JobHandle.CombineDependencies(disposeHandle, obstacleHits.Dispose(bakeObstaclesHandle)); // wait to complete all the scheduled stuff calculateNeighborsHandle.Complete(); gridWidth = scanSettings.gridWidth; gridDepth = scanSettings.gridDepth; isGridCreated = true; #if DEBUG_RENDER RecalculateDebug(); #endif }