static void HandleCompletePath(ComponentDataFromEntity <LocalToWorld> localToWorldFromEntity, Entity entity, Rotation rotation, ref NavAgent agent, Parent surface, Translation translation, PhysicsWorld physicsWorld, float elapsedSeconds, EntityCommandBuffer.ParallelWriter commandBuffer, int entityInQueryIndex, NavSettings settings)
        {
            var rayInput = new RaycastInput
            {
                Start  = localToWorldFromEntity[entity].Position + agent.Offset,
                End    = math.forward(rotation.Value) * settings.ObstacleRaycastDistanceMax,
                Filter = new CollisionFilter
                {
                    BelongsTo    = NavUtil.ToBitMask(settings.ColliderLayer),
                    CollidesWith = NavUtil.ToBitMask(settings.ObstacleLayer)
                }
            };

            if (
                !surface.Value.Equals(agent.DestinationSurface) &&
                !NavUtil.ApproxEquals(translation.Value, agent.LocalDestination, settings.StoppingDistance) &&
                !physicsWorld.CastRay(rayInput, out _)
                )
            {
                agent.JumpSeconds = elapsedSeconds;

                commandBuffer.RemoveComponent <NavWalking>(entityInQueryIndex, entity);
                commandBuffer.RemoveComponent <NavSteering>(entityInQueryIndex, entity);
                commandBuffer.AddComponent <NavJumping>(entityInQueryIndex, entity);
                commandBuffer.AddComponent <NavPlanning>(entityInQueryIndex, entity);

                return;
            }

            commandBuffer.RemoveComponent <NavWalking>(entityInQueryIndex, entity);
            commandBuffer.RemoveComponent <NavSteering>(entityInQueryIndex, entity);
            commandBuffer.RemoveComponent <NavDestination>(entityInQueryIndex, entity);
        }
예제 #2
0
        protected override JobHandle OnUpdate(JobHandle inputDeps)
        {
            var commandBuffer          = barrier.CreateCommandBuffer().ToConcurrent();
            var physicsWorld           = buildPhysicsWorld.PhysicsWorld;
            var localToWorldFromEntity = GetComponentDataFromEntity <LocalToWorld>(true);

            var createJob = Entities
                            .WithChangeFilter <NavNeedsDestination>()
                            .WithReadOnly(localToWorldFromEntity)
                            .WithReadOnly(physicsWorld)
                            .ForEach((Entity entity, int entityInQueryIndex, ref NavAgent agent, in NavNeedsDestination destination) =>
            {
                var collider = SphereCollider.Create(
                    new SphereGeometry()
                {
                    Center = destination.Value,
                    Radius = 1
                },
                    new CollisionFilter()
                {
                    BelongsTo    = NavUtil.ToBitMask(NavConstants.COLLIDER_LAYER),
                    CollidesWith = NavUtil.ToBitMask(NavConstants.SURFACE_LAYER),
                }
                    );

                unsafe
                {
                    var castInput = new ColliderCastInput()
                    {
                        Collider    = (Collider *)collider.GetUnsafePtr(),
                        Orientation = quaternion.identity
                    };

                    if (!physicsWorld.CastCollider(castInput, out ColliderCastHit hit) || hit.RigidBodyIndex == -1)
                    {
                        commandBuffer.RemoveComponent <NavNeedsDestination>(entityInQueryIndex, entity);    // Ignore invalid destinations.
                        return;
                    }

                    agent.DestinationSurface = physicsWorld.Bodies[hit.RigidBodyIndex].Entity;

                    agent.LocalDestination = NavUtil.MultiplyPoint3x4(
                        math.inverse(localToWorldFromEntity[agent.DestinationSurface].Value),
                        destination.Value
                        ) + agent.Offset;

                    commandBuffer.AddComponent <NavPlanning>(entityInQueryIndex, entity);
                }
            })
                            .WithName("CreateDestinationJob")
                            .Schedule(JobHandle.CombineDependencies(
                                          inputDeps,
                                          buildPhysicsWorld.FinalJobHandle
                                          ));

            barrier.AddJobHandleForProducer(createJob);

            return(createJob);
        }
        protected override void OnUpdate()
        {
            var physicsWorld = buildPhysicsWorld.PhysicsWorld;
            var settings     = navSystem.Settings;

            Dependency = JobHandle.CombineDependencies(Dependency, buildPhysicsWorld.GetOutputDependency());

            var isDebugging = IsDebugging;

            Entities
            .WithNone <NavProblem>()
            .WithNone <NavPlanning, NavJumping, NavFalling>()
            .WithAll <NavWalking, LocalToParent, NavTerrainCapable>()
            .WithReadOnly(physicsWorld)
            .ForEach((Entity entity, int entityInQueryIndex, ref Translation translation, ref NavAgent agent, in LocalToWorld localToWorld, in Parent surface) =>
            {
                var rayInput = new RaycastInput
                {
                    Start  = localToWorld.Position + agent.Offset,
                    End    = -math.up() * settings.SurfaceRaycastDistanceMax,
                    Filter = new CollisionFilter()
                    {
                        BelongsTo    = NavUtil.ToBitMask(settings.ColliderLayer),
                        CollidesWith = NavUtil.ToBitMask(settings.SurfaceLayer),
                    }
                };

                if (physicsWorld.CastRay(rayInput, out RaycastHit hit))
                {
                    if (isDebugging)
                    {
                        UnityEngine.Debug.DrawLine(hit.Position, hit.Position + hit.SurfaceNormal * 15, UnityEngine.Color.green);
                        UnityEngine.Debug.DrawLine(hit.Position, hit.Position + localToWorld.Up * 7, UnityEngine.Color.cyan);
                        UnityEngine.Debug.DrawLine(hit.Position, hit.Position + localToWorld.Right * 7, UnityEngine.Color.cyan);
                        UnityEngine.Debug.DrawLine(hit.Position, hit.Position + localToWorld.Forward * 7, UnityEngine.Color.cyan);
                    }

                    agent.SurfacePointNormal = hit.SurfaceNormal;

                    var currentPosition = translation.Value;
                    currentPosition.y   = hit.Position.y + agent.Offset.y;
                    translation.Value   = currentPosition;
                }
            })
        protected override void OnUpdate()
        {
            var commandBuffer          = barrier.CreateCommandBuffer().AsParallelWriter();
            var elapsedSeconds         = (float)Time.ElapsedTime;
            var deltaSeconds           = Time.DeltaTime;
            var physicsWorld           = buildPhysicsWorld.PhysicsWorld;
            var pathBufferFromEntity   = GetBufferFromEntity <NavPathBufferElement>(true);
            var localToWorldFromEntity = GetComponentDataFromEntity <LocalToWorld>(true);

            Dependency = JobHandle.CombineDependencies(Dependency, buildPhysicsWorld.GetOutputDependency());

            Entities
            .WithNone <NavHasProblem, NavPlanning, NavJumping>()
            .WithAll <NavLerping, LocalToParent>()
            .WithReadOnly(pathBufferFromEntity)
            .WithReadOnly(localToWorldFromEntity)
            .WithReadOnly(physicsWorld)
            .ForEach((Entity entity, int entityInQueryIndex, ref NavAgent agent, ref Translation translation, ref Rotation rotation, in Parent surface) =>
            {
                if (!pathBufferFromEntity.HasComponent(entity) || agent.DestinationSurface.Equals(Entity.Null))
                {
                    return;
                }

                var pathBuffer = pathBufferFromEntity[entity];

                if (pathBuffer.Length == 0)
                {
                    return;
                }

                if (agent.PathBufferIndex >= pathBuffer.Length)
                {
                    --agent.PathBufferIndex;
                    return;
                }

                var localDestination = agent.LocalDestination;
                var localWaypoint    = pathBuffer[agent.PathBufferIndex].Value;

                if (
                    NavUtil.ApproxEquals(translation.Value, localWaypoint, 1) &&
                    ++agent.PathBufferIndex > pathBuffer.Length - 1
                    )
                {
                    var rayInput = new RaycastInput
                    {
                        Start  = localToWorldFromEntity[entity].Position + agent.Offset,
                        End    = math.forward(rotation.Value) * NavConstants.OBSTACLE_RAYCAST_DISTANCE_MAX,
                        Filter = new CollisionFilter
                        {
                            BelongsTo    = NavUtil.ToBitMask(NavConstants.COLLIDER_LAYER),
                            CollidesWith = NavUtil.ToBitMask(NavConstants.OBSTACLE_LAYER)
                        }
                    };

                    if (
                        !surface.Value.Equals(agent.DestinationSurface) &&
                        !NavUtil.ApproxEquals(translation.Value, localDestination, 1) &&
                        !physicsWorld.CastRay(rayInput, out RaycastHit hit)
                        )
                    {
                        agent.JumpSeconds = elapsedSeconds;
                        commandBuffer.AddComponent <NavJumping>(entityInQueryIndex, entity);
                        commandBuffer.AddComponent <NavPlanning>(entityInQueryIndex, entity);
                        return;
                    }

                    commandBuffer.RemoveComponent <NavLerping>(entityInQueryIndex, entity);
                    commandBuffer.RemoveComponent <NavNeedsDestination>(entityInQueryIndex, entity);
                    agent.PathBufferIndex = 0;
                    return;
                }

                translation.Value = Vector3.MoveTowards(translation.Value, localWaypoint, agent.TranslationSpeed * deltaSeconds);

                var lookAt = NavUtil.MultiplyPoint3x4(     // To world (from local in terms of destination surface).
                    localToWorldFromEntity[agent.DestinationSurface].Value,
                    localWaypoint
                    );

                lookAt = NavUtil.MultiplyPoint3x4(     // To local (in terms of agent's current surface).
                    math.inverse(localToWorldFromEntity[surface.Value].Value),
                    lookAt
                    );

                lookAt.y = translation.Value.y;

                var lookRotation = quaternion.LookRotationSafe(lookAt - translation.Value, math.up());

                if (math.length(agent.SurfacePointNormal) > 0.01f)
                {
                    lookRotation = Quaternion.FromToRotation(math.up(), agent.SurfacePointNormal) * lookRotation;
                }

                rotation.Value = math.slerp(rotation.Value, lookRotation, deltaSeconds / agent.RotationSpeed);
            })
            .WithName("NavWalkJob")
            .ScheduleParallel();

            barrier.AddJobHandleForProducer(Dependency);

            var jumpBufferFromEntity = GetBufferFromEntity <NavJumpBufferElement>();
            var fallingFromEntity    = GetComponentDataFromEntity <NavFalling>();

            Entities
            .WithNone <NavHasProblem>()
            .WithAny <NavFalling, NavJumping>()
            .WithAll <LocalToParent>()
            .WithReadOnly(fallingFromEntity)
            .WithReadOnly(jumpBufferFromEntity)
            .WithReadOnly(localToWorldFromEntity)
            .ForEach((Entity entity, int entityInQueryIndex, ref Translation translation, in NavAgent agent, in Parent surface) =>
            {
                if (agent.DestinationSurface.Equals(Entity.Null))
                {
                    return;
                }

                commandBuffer.AddComponent <NavPlanning>(entityInQueryIndex, entity);

                if (!jumpBufferFromEntity.HasComponent(entity))
                {
                    return;
                }
                var jumpBuffer = jumpBufferFromEntity[entity];

                if (jumpBuffer.Length == 0 && !fallingFromEntity.HasComponent(entity))
                {
                    return;
                }

                var destination = NavUtil.MultiplyPoint3x4(
                    localToWorldFromEntity[agent.DestinationSurface].Value,
                    agent.LocalDestination
                    );

                var velocity  = Vector3.Distance(translation.Value, destination) / (math.sin(2 * math.radians(agent.JumpDegrees)) / agent.JumpGravity);
                var yVelocity = math.sqrt(velocity) * math.sin(math.radians(agent.JumpDegrees));
                var waypoint  = translation.Value + math.up() * float.NegativeInfinity;

                if (!fallingFromEntity.HasComponent(entity))
                {
                    var xVelocity = math.sqrt(velocity) * math.cos(math.radians(agent.JumpDegrees)) * agent.JumpSpeedMultiplierX;

                    waypoint = NavUtil.MultiplyPoint3x4(     // To world (from local in terms of destination surface).
                        localToWorldFromEntity[agent.DestinationSurface].Value,
                        jumpBuffer[0].Value
                        );

                    waypoint = NavUtil.MultiplyPoint3x4(     // To local (in terms of agent's current surface).
                        math.inverse(localToWorldFromEntity[surface.Value].Value),
                        waypoint
                        );

                    translation.Value = Vector3.MoveTowards(translation.Value, waypoint, xVelocity * deltaSeconds);
                }

                translation.Value.y += (yVelocity - (elapsedSeconds - agent.JumpSeconds) * agent.JumpGravity) * deltaSeconds * agent.JumpSpeedMultiplierY;

                if (elapsedSeconds - agent.JumpSeconds >= NavConstants.JUMP_SECONDS_MAX)
                {
                    commandBuffer.RemoveComponent <NavJumping>(entityInQueryIndex, entity);
                    commandBuffer.AddComponent <NavFalling>(entityInQueryIndex, entity);
                }

                if (!NavUtil.ApproxEquals(translation.Value, waypoint, 1))
                {
                    return;
                }

                commandBuffer.AddComponent <NavNeedsSurface>(entityInQueryIndex, entity);
                commandBuffer.RemoveComponent <NavJumping>(entityInQueryIndex, entity);
            })
예제 #5
0
        protected override void OnUpdate()
        {
            var commandBuffer = barrier.CreateCommandBuffer().AsParallelWriter();
            var defaultBasis  = World.GetExistingSystem <NavBasisSystem>().DefaultBasis;

            // Below job is needed because Unity.Physics removes the Parent
            // component for dynamic bodies.
            Entities
            .WithNone <Parent>()
            .ForEach((Entity entity, int entityInQueryIndex, in NavSurface surface) =>
            {
                if (surface.Basis.Equals(Entity.Null))
                {
                    commandBuffer.AddComponent(entityInQueryIndex, entity, new Parent
                    {
                        Value = defaultBasis
                    });
                }
                else
                {
                    commandBuffer.AddComponent(entityInQueryIndex, entity, new Parent
                    {
                        Value = surface.Basis
                    });
                }

                commandBuffer.AddComponent <LocalToParent>(entityInQueryIndex, entity);
            })
            .WithoutBurst()
            .WithName("NavAddParentToSurfaceJob")
            .ScheduleParallel();

            barrier.AddJobHandleForProducer(Dependency);

            // Below job is needed so users don't have to manually add the
            // Parent and LocalToParent components when spawning agents.
            Entities
            .WithNone <NavHasProblem, Parent>()
            .ForEach((Entity entity, int entityInQueryIndex, in NavAgent agent) =>
            {
                commandBuffer.AddComponent <Parent>(entityInQueryIndex, entity);
                commandBuffer.AddComponent <LocalToParent>(entityInQueryIndex, entity);
            })
            .WithoutBurst()
            .WithName("NavAddParentToAgentJob")
            .ScheduleParallel();

            barrier.AddJobHandleForProducer(Dependency);

            // Below job is needed because Unity.Transforms assumes that
            // children should be scaled by their surface by automatically
            // providing them with a CompositeScale.
            Entities
            .WithAll <CompositeScale>()
            .WithAny <NavSurface, NavBasis>()
            .ForEach((Entity entity, int entityInQueryIndex) =>
            {
                commandBuffer.RemoveComponent <CompositeScale>(entityInQueryIndex, entity);
            })
            .WithName("NavRemoveCompositeScaleJob")
            .ScheduleParallel();

            barrier.AddJobHandleForProducer(Dependency);

            var elapsedSeconds       = (float)Time.ElapsedTime;
            var physicsWorld         = buildPhysicsWorld.PhysicsWorld;
            var jumpBufferFromEntity = GetBufferFromEntity <NavJumpBufferElement>();
            var map = needsSurfaceMap;

            Dependency = JobHandle.CombineDependencies(Dependency, buildPhysicsWorld.GetOutputDependency());

            Entities
            .WithNone <NavHasProblem, NavFalling, NavJumping>()
            .WithAll <NavNeedsSurface, LocalToParent>()
            .WithReadOnly(physicsWorld)
            .WithNativeDisableParallelForRestriction(jumpBufferFromEntity)
            .WithNativeDisableContainerSafetyRestriction(map)
            .ForEach((Entity entity, int entityInQueryIndex, ref NavAgent agent, ref Parent surface, ref Translation translation, in LocalToWorld localToWorld) =>
            {
                if (
                    !surface.Value.Equals(Entity.Null) &&
                    map.TryGetValue(entity.Index, out bool needsSurface) &&
                    !map.TryAdd(entity.Index, false)
                    )
                {
                    return;
                }

                var rayInput = new RaycastInput
                {
                    Start  = localToWorld.Position + agent.Offset,
                    End    = -localToWorld.Up * NavConstants.SURFACE_RAYCAST_DISTANCE_MAX,
                    Filter = new CollisionFilter()
                    {
                        BelongsTo    = NavUtil.ToBitMask(NavConstants.COLLIDER_LAYER),
                        CollidesWith = NavUtil.ToBitMask(NavConstants.SURFACE_LAYER),
                    }
                };

                if (!physicsWorld.CastRay(rayInput, out RaycastHit hit))
                {
                    if (++agent.SurfaceRaycastCount >= NavConstants.SURFACE_RAYCAST_MAX)
                    {
                        agent.FallSeconds = elapsedSeconds;

                        commandBuffer.RemoveComponent <NavNeedsSurface>(entityInQueryIndex, entity);
                        commandBuffer.AddComponent <NavFalling>(entityInQueryIndex, entity);
                    }

                    return;
                }

                agent.SurfaceRaycastCount = 0;
                surface.Value             = physicsWorld.Bodies[hit.RigidBodyIndex].Entity;
                commandBuffer.RemoveComponent <NavNeedsSurface>(entityInQueryIndex, entity);

                translation.Value.y = hit.Position.y + agent.Offset.y;

                if (!jumpBufferFromEntity.HasComponent(entity))
                {
                    return;
                }
                var jumpBuffer = jumpBufferFromEntity[entity];
                if (jumpBuffer.Length < 1)
                {
                    return;
                }

                translation.Value = jumpBuffer[0].Value + agent.Offset;

                jumpBuffer.Clear();

                commandBuffer.AddComponent <NavPlanning>(entityInQueryIndex, entity);
            })
            .WithName("NavSurfaceTrackingJob")
            .ScheduleParallel();

            barrier.AddJobHandleForProducer(Dependency);
        }
예제 #6
0
        protected override void OnUpdate()
        {
            var commandBuffer = barrier.CreateCommandBuffer().AsParallelWriter();
            var defaultBasis  = World.GetExistingSystem <NavBasisSystem>().DefaultBasis;

            // Prevents Unity.Physics from removing the Parent component from dynamic bodies:
            Entities
            .WithNone <Parent>()
            .ForEach((Entity entity, int entityInQueryIndex, in NavSurface surface) =>
            {
                if (surface.Basis.Equals(Entity.Null))
                {
                    commandBuffer.AddComponent(entityInQueryIndex, entity, new Parent
                    {
                        Value = defaultBasis
                    });
                }
                else
                {
                    commandBuffer.AddComponent(entityInQueryIndex, entity, new Parent
                    {
                        Value = surface.Basis
                    });
                }

                commandBuffer.AddComponent <LocalToParent>(entityInQueryIndex, entity);
            })
            .WithName("NavAddParentToSurfaceJob")
            .ScheduleParallel();

            barrier.AddJobHandleForProducer(Dependency);

            // Adds Parent and LocalToParent components when to agents:
            Entities
            .WithNone <NavProblem, Parent>()
            .ForEach((Entity entity, int entityInQueryIndex, in NavAgent agent) =>
            {
                commandBuffer.AddComponent <Parent>(entityInQueryIndex, entity);
                commandBuffer.AddComponent <LocalToParent>(entityInQueryIndex, entity);
            })
            .WithName("NavAddParentToAgentJob")
            .ScheduleParallel();

            barrier.AddJobHandleForProducer(Dependency);

            // Prevents Unity.Transforms from assuming that children should be scaled by their parent:
            Entities
            .WithAll <CompositeScale>()
            .WithAny <NavSurface, NavBasis>()
            .ForEach((Entity entity, int entityInQueryIndex) =>
            {
                commandBuffer.RemoveComponent <CompositeScale>(entityInQueryIndex, entity);
            })
            .WithName("NavRemoveCompositeScaleJob")
            .ScheduleParallel();

            barrier.AddJobHandleForProducer(Dependency);

            var elapsedSeconds       = (float)Time.ElapsedTime;
            var physicsWorld         = buildPhysicsWorld.PhysicsWorld;
            var settings             = navSystem.Settings;
            var jumpBufferFromEntity = GetBufferFromEntity <NavJumpBufferElement>();
            var pathBufferFromEntity = GetBufferFromEntity <NavPathBufferElement>();

            Dependency = JobHandle.CombineDependencies(Dependency, buildPhysicsWorld.GetOutputDependency());

            Entities
            .WithNone <NavProblem, NavFalling, NavJumping>()
            .WithAll <NavNeedsSurface, LocalToParent>()
            .WithReadOnly(physicsWorld)
            .WithNativeDisableParallelForRestriction(jumpBufferFromEntity)
            .WithNativeDisableParallelForRestriction(pathBufferFromEntity)
            .ForEach((Entity entity, int entityInQueryIndex, ref NavAgent agent, ref Parent surface, ref Translation translation, in LocalToWorld localToWorld) =>
            {
                if (!surface.Value.Equals(Entity.Null) && false)
                {
                    return;
                }

                var rayInput = new RaycastInput
                {
                    Start  = localToWorld.Position + agent.Offset,
                    End    = -localToWorld.Up * settings.SurfaceRaycastDistanceMax,
                    Filter = new CollisionFilter()
                    {
                        BelongsTo    = NavUtil.ToBitMask(settings.ColliderLayer),
                        CollidesWith = NavUtil.ToBitMask(settings.SurfaceLayer),
                    }
                };

                if (!physicsWorld.CastRay(rayInput, out RaycastHit hit))
                {
                    if (++agent.SurfaceRaycastCount >= settings.SurfaceRaycastMax)
                    {
                        agent.FallSeconds = elapsedSeconds;

                        commandBuffer.RemoveComponent <NavNeedsSurface>(entityInQueryIndex, entity);
                        commandBuffer.AddComponent <NavFalling>(entityInQueryIndex, entity);
                    }

                    return;
                }

                agent.SurfaceRaycastCount = 0;
                surface.Value             = physicsWorld.Bodies[hit.RigidBodyIndex].Entity;
                commandBuffer.RemoveComponent <NavNeedsSurface>(entityInQueryIndex, entity);

                translation.Value.y = hit.Position.y + agent.Offset.y;

                if (!jumpBufferFromEntity.HasComponent(entity))
                {
                    return;
                }
                var jumpBuffer = jumpBufferFromEntity[entity];
                if (jumpBuffer.Length < 1)
                {
                    return;
                }

                translation.Value = jumpBuffer[0].Value + agent.Offset;

                jumpBuffer.Clear();

                if (pathBufferFromEntity.HasComponent(entity))
                {
                    pathBufferFromEntity[entity].Clear();
                }

                commandBuffer.AddComponent <NavPlanning>(entityInQueryIndex, entity);
            })
            .WithName("NavSurfaceTrackingJob")
            .ScheduleParallel();

            var localToWorldFromEntity = GetComponentDataFromEntity <LocalToWorld>(true);

            ////////////////////////////////////////////////////////////////////////////////////
            ////////////////////////////////////////////////////////////////////////////////////
            // TODO : Move following jobs and related code into transform extensions package. //
            ////////////////////////////////////////////////////////////////////////////////////
            ////////////////////////////////////////////////////////////////////////////////////

            // Corrects the translation of children with a parent not at the origin:
            Entities
            .WithChangeFilter <PreviousParent>()
            .WithAny <NavFixTranslation>()
            .WithReadOnly(localToWorldFromEntity)
            .ForEach((Entity entity, int entityInQueryIndex, ref Translation translation, in PreviousParent previousParent, in Parent parent) =>
            {
                if (previousParent.Value.Equals(Entity.Null) || !localToWorldFromEntity.HasComponent(parent.Value))
                {
                    return;
                }

                var parentTransform = localToWorldFromEntity[parent.Value];

                if (parentTransform.Position.Equals(float3.zero))
                {
                    commandBuffer.RemoveComponent <NavFixTranslation>(entityInQueryIndex, entity);
                    return;
                }

                translation.Value = NavUtil.MultiplyPoint3x4(
                    math.inverse(parentTransform.Value),
                    translation.Value
                    );

                commandBuffer.RemoveComponent <NavFixTranslation>(entityInQueryIndex, entity);
            })
예제 #7
0
        protected override void OnUpdate()
        {
            var commandBuffer          = barrier.CreateCommandBuffer().AsParallelWriter();
            var elapsedSeconds         = (float)Time.ElapsedTime;
            var localToWorldFromEntity = GetComponentDataFromEntity <LocalToWorld>(true);
            var physicsWorld           = buildPhysicsWorld.PhysicsWorld;
            var settings = navSystem.Settings;

            Entities
            .WithNone <NavProblem>()
            .WithChangeFilter <NavDestination>()
            .WithReadOnly(localToWorldFromEntity)
            .WithReadOnly(physicsWorld)
            .ForEach((Entity entity, int entityInQueryIndex, ref NavAgent agent, in NavDestination destination) =>
            {
                if (elapsedSeconds - agent.DestinationSeconds < settings.DestinationRateLimitSeconds)
                {
                    commandBuffer.AddComponent <NavDestination>(entityInQueryIndex, entity, destination);    // So that the change filter applies next frame.
                    return;
                }

                var collider = SphereCollider.Create(
                    new SphereGeometry()
                {
                    Center = destination.WorldPoint,
                    Radius = settings.DestinationSurfaceColliderRadius
                },
                    new CollisionFilter()
                {
                    BelongsTo    = NavUtil.ToBitMask(settings.ColliderLayer),
                    CollidesWith = NavUtil.ToBitMask(settings.SurfaceLayer),
                }
                    );

                unsafe
                {
                    var castInput = new ColliderCastInput()
                    {
                        Collider    = (Collider *)collider.GetUnsafePtr(),
                        Orientation = quaternion.identity
                    };

                    if (!physicsWorld.CastCollider(castInput, out ColliderCastHit hit))
                    {
                        commandBuffer.RemoveComponent <NavDestination>(entityInQueryIndex, entity);    // Ignore invalid destinations.
                        return;
                    }

                    var localDestination = destination.WorldPoint.ToLocal(localToWorldFromEntity[hit.Entity]) + agent.Offset;

                    if (NavUtil.ApproxEquals(localDestination, agent.LocalDestination, destination.Tolerance))
                    {
                        return;
                    }

                    if (destination.Teleport)
                    {
                        commandBuffer.SetComponent <Parent>(entityInQueryIndex, entity, new Parent
                        {
                            Value = hit.Entity
                        });

                        commandBuffer.SetComponent <Translation>(entityInQueryIndex, entity, new Translation
                        {
                            Value = localDestination
                        });

                        commandBuffer.RemoveComponent <NavDestination>(entityInQueryIndex, entity);

                        return;
                    }

                    agent.DestinationSurface = physicsWorld.Bodies[hit.RigidBodyIndex].Entity;
                    agent.LocalDestination   = localDestination;
                    agent.DestinationSeconds = elapsedSeconds;

                    commandBuffer.AddComponent <NavPlanning>(entityInQueryIndex, entity);
                }
            })
            .WithName("CreateDestinationJob")
            .ScheduleParallel();

            barrier.AddJobHandleForProducer(Dependency);
            buildPhysicsWorld.AddInputDependencyToComplete(Dependency);
        }
예제 #8
0
        protected override void OnUpdate()
        {
            var commandBuffer          = barrier.CreateCommandBuffer().AsParallelWriter();
            var physicsWorld           = buildPhysicsWorld.PhysicsWorld;
            var localToWorldFromEntity = GetComponentDataFromEntity <LocalToWorld>(true);

            Dependency = JobHandle.CombineDependencies(Dependency, buildPhysicsWorld.GetOutputDependency());

            Entities
            .WithNone <NavHasProblem>()
            .WithChangeFilter <NavNeedsDestination>()
            .WithReadOnly(localToWorldFromEntity)
            .WithReadOnly(physicsWorld)
            .ForEach((Entity entity, int entityInQueryIndex, ref NavAgent agent, in NavNeedsDestination needsDestination) =>
            {
                var collider = SphereCollider.Create(
                    new SphereGeometry()
                {
                    Center = needsDestination.Destination,
                    Radius = NavConstants.DESTINATION_SURFACE_COLLIDER_RADIUS
                },
                    new CollisionFilter()
                {
                    BelongsTo    = NavUtil.ToBitMask(NavConstants.COLLIDER_LAYER),
                    CollidesWith = NavUtil.ToBitMask(NavConstants.SURFACE_LAYER),
                }
                    );

                unsafe
                {
                    var castInput = new ColliderCastInput()
                    {
                        Collider    = (Collider *)collider.GetUnsafePtr(),
                        Orientation = quaternion.identity
                    };

                    if (!physicsWorld.CastCollider(castInput, out ColliderCastHit hit))
                    {
                        commandBuffer.RemoveComponent <NavNeedsDestination>(entityInQueryIndex, entity);    // Ignore invalid destinations.
                        return;
                    }

                    var destination = NavUtil.MultiplyPoint3x4(
                        math.inverse(localToWorldFromEntity[hit.Entity].Value),
                        needsDestination.Destination
                        ) + agent.Offset;

                    if (needsDestination.Teleport)
                    {
                        commandBuffer.SetComponent <Parent>(entityInQueryIndex, entity, new Parent
                        {
                            Value = hit.Entity
                        });

                        commandBuffer.SetComponent <Translation>(entityInQueryIndex, entity, new Translation
                        {
                            Value = destination
                        });

                        commandBuffer.RemoveComponent <NavNeedsDestination>(entityInQueryIndex, entity);

                        return;
                    }

                    agent.DestinationSurface = physicsWorld.Bodies[hit.RigidBodyIndex].Entity;
                    agent.LocalDestination   = destination;

                    commandBuffer.AddComponent <NavPlanning>(entityInQueryIndex, entity);
                }
            })
            .WithName("CreateDestinationJob")
            .ScheduleParallel();

            barrier.AddJobHandleForProducer(Dependency);
        }
예제 #9
0
        protected override JobHandle OnUpdate(JobHandle inputDeps)
        {
            var commandBuffer = barrier.CreateCommandBuffer().ToConcurrent();
            var defaultBasis  = World.GetExistingSystem <NavBasisSystem>().DefaultBasis;

            // Below job is needed because Unity.Physics removes the Parent
            // component for dynamic bodies.
            var addParentJob = Entities
                               .WithNone <Parent>()
                               .ForEach((Entity entity, int entityInQueryIndex, in NavSurface surface) =>
            {
                if (surface.Basis.Equals(Entity.Null))
                {
                    commandBuffer.AddComponent(entityInQueryIndex, entity, new Parent
                    {
                        Value = defaultBasis
                    });
                }
                else
                {
                    commandBuffer.AddComponent(entityInQueryIndex, entity, new Parent
                    {
                        Value = surface.Basis
                    });
                }

                commandBuffer.AddComponent(entityInQueryIndex, entity, typeof(LocalToParent));
            })
                               .WithoutBurst()
                               .WithName("NavAddParentToSurfaceJob")
                               .Schedule(inputDeps);

            barrier.AddJobHandleForProducer(addParentJob);

            // Below job is needed because Unity.Transforms assumes that
            // children should be scaled by their surface by automatically
            // providing them with a CompositeScale.
            var removeCompositeScaleJob = Entities
                                          .WithAll <CompositeScale>()
                                          .WithAny <NavSurface, NavBasis>()
                                          .ForEach((Entity entity, int entityInQueryIndex) =>
            {
                commandBuffer.RemoveComponent <CompositeScale>(entityInQueryIndex, entity);
            })
                                          .WithName("NavRemoveCompositeScaleJob")
                                          .Schedule(addParentJob);

            barrier.AddJobHandleForProducer(removeCompositeScaleJob);

            var elapsedSeconds         = (float)Time.ElapsedTime;
            var physicsWorld           = buildPhysicsWorld.PhysicsWorld;
            var jumpBufferFromEntity   = GetBufferFromEntity <NavJumpBufferElement>();
            var localToWorldFromEntity = GetComponentDataFromEntity <LocalToWorld>(true);

            var navSurfaceTrackingJob = Entities
                                        .WithNone <NavFalling, NavJumping>()
                                        .WithAll <NavNeedsSurface, LocalToParent>()
                                        .WithReadOnly(localToWorldFromEntity)
                                        .WithReadOnly(physicsWorld)
                                        .WithNativeDisableParallelForRestriction(jumpBufferFromEntity)
                                        .ForEach((Entity entity, int entityInQueryIndex, ref NavAgent agent, ref Parent surface, ref Translation translation) =>
            {
                if (
                    !surface.Value.Equals(Entity.Null) &&
                    needsSurfaceDictionary.GetOrAdd(entity.Index, true)
                    )
                {
                    return;
                }

                needsSurfaceDictionary[entity.Index] = false;

                var rayInput = new RaycastInput
                {
                    Start  = localToWorldFromEntity[entity].Position + agent.Offset,
                    End    = -math.up() * NavConstants.SURFACE_RAYCAST_DISTANCE_MAX,
                    Filter = new CollisionFilter()
                    {
                        BelongsTo    = NavUtil.ToBitMask(NavConstants.COLLIDER_LAYER),
                        CollidesWith = NavUtil.ToBitMask(NavConstants.SURFACE_LAYER),
                    }
                };

                if (!physicsWorld.CastRay(rayInput, out RaycastHit hit) || hit.RigidBodyIndex == -1)
                {
                    if (++agent.SurfaceRaycastCount >= NavConstants.SURFACE_RAYCAST_MAX)
                    {
                        agent.FallSeconds = elapsedSeconds;

                        commandBuffer.RemoveComponent <NavNeedsSurface>(entityInQueryIndex, entity);
                        commandBuffer.AddComponent <NavFalling>(entityInQueryIndex, entity);
                    }

                    return;
                }

                agent.SurfaceRaycastCount = 0;
                surface.Value             = physicsWorld.Bodies[hit.RigidBodyIndex].Entity;
                commandBuffer.RemoveComponent <NavNeedsSurface>(entityInQueryIndex, entity);

                if (!jumpBufferFromEntity.Exists(entity))
                {
                    return;
                }
                var jumpBuffer = jumpBufferFromEntity[entity];
                if (jumpBuffer.Length < 1)
                {
                    return;
                }

                translation.Value = jumpBuffer[0].Value + agent.Offset;

                jumpBuffer.Clear();

                commandBuffer.AddComponent <NavPlanning>(entityInQueryIndex, entity);
            })
                                        .WithoutBurst()
                                        .WithName("NavSurfaceTrackingJob")
                                        .Schedule(
                JobHandle.CombineDependencies(
                    removeCompositeScaleJob,
                    buildPhysicsWorld.FinalJobHandle
                    )
                );

            barrier.AddJobHandleForProducer(navSurfaceTrackingJob);

            return(navSurfaceTrackingJob);
        }
예제 #10
0
        protected override void OnUpdate()
        {
            var physicsWorld     = buildPhysicsWorld.PhysicsWorld;
            var settings         = navSystem.Settings;
            var flockingSettings = navSystem.FlockingSettings;
            var isDebugging      = IsDebugging;

            Entities
            .WithNone <NavProblem>()
            .WithNone <NavPlanning, NavJumping, NavFalling>()
            .WithAll <NavObstacleSteering>()
            .WithAll <NavWalking, NavFlocking, LocalToParent>()
            .WithReadOnly(physicsWorld)
            .ForEach((Entity entity, int entityInQueryIndex, ref Translation translation, ref NavAgent agent, ref NavSteering steering, in LocalToWorld localToWorld, in Rotation rotation, in Parent surface) =>
            {
                var averageHitDirection = float3.zero;
                var clostestHitDistance = agent.ObstacleAversionDistance;
                var hits = 0;

                for (var i = 0; i < NUM_RAYS; ++i)
                {
                    var rayModifier  = quaternion.AxisAngle(localToWorld.Up, i / (NUM_RAYS - 1) * math.radians(flockingSettings.CollisionCastingAngle * 2 - flockingSettings.CollisionCastingAngle));
                    var rayDirection = math.mul(math.mul(rotation.Value, rayModifier), math.forward());

                    if (isDebugging)
                    {
                        Debug.DrawRay(localToWorld.Position, rayDirection * agent.ObstacleAversionDistance, Color.cyan);
                    }

                    var ray = new RaycastInput
                    {
                        Start  = localToWorld.Position,
                        End    = localToWorld.Position + rayDirection * agent.ObstacleAversionDistance,
                        Filter = new CollisionFilter()
                        {
                            BelongsTo    = NavUtil.ToBitMask(settings.ColliderLayer),
                            CollidesWith = NavUtil.ToBitMask(settings.ObstacleLayer),
                        }
                    };

                    if (physicsWorld.CastRay(ray, out RaycastHit hit))
                    {
                        var distance = math.distance(localToWorld.Position, hit.Position);

                        clostestHitDistance  = math.select(clostestHitDistance, distance, distance < clostestHitDistance);
                        averageHitDirection += localToWorld.Position - hit.Position;

                        ++hits;

                        if (isDebugging)
                        {
                            Debug.DrawLine(localToWorld.Position, hit.Position, Color.red);
                        }
                    }
                }

                averageHitDirection /= hits;

                var scalar = 1 - (clostestHitDistance / agent.ObstacleAversionDistance);

                // Steer away from the average hit direction; addiontally, scale the steering vector by the closest hit distance. Otherwise, the entity just bounces off walls and spins out of control.
                steering.CollisionAvoidanceSteering = flockingSettings.ObstacleCollisionAvoidanceStrength * math.normalizesafe(averageHitDirection) * scalar;
            })