Beispiel #1
0
        /// <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();
        }
Beispiel #2
0
            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);
            }
        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;
        }
Beispiel #4
0
        /// <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
        }