/// <summary>
        /// Tries to move towards the target position using the attached NavigationComponent asynchronously
        /// </summary>
        /// <param name="targetPosition"></param>
        /// <returns></returns>
        protected IEnumerator <Vector3> Move(Vector3 targetPosition)
        {
            NavigationComponent navigationComponent = Entity.Get <NavigationComponent>();

            List <Vector3> pathPoints = new List <Vector3>();

            if (navigationComponent == null || navigationComponent.NavigationMesh == null)
            {
                pathPoints = new List <Vector3> {
                    Entity.Transform.WorldMatrix.TranslationVector, targetPosition
                };
            }
            else
            {
                if (!navigationComponent.TryFindPath(targetPosition, pathPoints))
                {
                    yield break;
                }
            }

            Path     navigationPath = new Path(pathPoints.ToArray());
            Waypoint nextWaypoint   = navigationPath.Waypoints[0];

            while (nextWaypoint != null)
            {
                Vector3 targetSpeed = Vector3.Zero;
                if (!Drone.Stunned)
                {
                    // Move towards target when having a waypoint
                    Vector3 dir = nextWaypoint.Position - Entity.Transform.WorldMatrix.TranslationVector;
                    dir.Y = 0;
                    var dist = dir.Length();

                    if (dist < MoveThreshold)
                    {
                        nextWaypoint = nextWaypoint.Next;
                        continue;
                    }

                    dir.Normalize();
                    Drone.UpdateBodyRotation(dir);

                    targetSpeed = dir * Drone.MaximumSpeed;
                    float dt            = (float)Game.UpdateTime.Elapsed.TotalSeconds;
                    var   estimatedDist = targetSpeed.Length() * dt;
                    if (estimatedDist > dist)
                    {
                        targetSpeed = dir * (dist / dt);
                    }
                }
                Drone.SetMovement(targetSpeed);
                yield return(nextWaypoint.Position);
            }

            // Stop when done moving
            Drone.SetMovement(Vector3.Zero);
        }
Beispiel #2
0
        public override void Update()
        {
            base.Update();

            Vector2 logicalMovement = Vector2.Zero;

            if (Input.IsKeyDown(Keys.A))
            {
                logicalMovement.X = -1.0f;
            }
            if (Input.IsKeyDown(Keys.D))
            {
                logicalMovement.X = 1.0f;
            }
            if (Input.IsKeyDown(Keys.W))
            {
                logicalMovement.Y = 1.0f;
            }
            if (Input.IsKeyDown(Keys.S))
            {
                logicalMovement.Y = -1.0f;
            }

            Vector3 worldMovement = Vector3.UnitX * logicalMovement.X + Vector3.UnitZ * -logicalMovement.Y;

            worldMovement.Normalize();

            Drone.SetMovement(worldMovement);

            if (worldMovement != Vector3.Zero)
            {
                Drone.UpdateBodyRotation(worldMovement);
            }

            if (Input.IsMousePositionLocked)
            {
                Size3   backbufferSize      = Game.GraphicsDevice.Presenter.BackBuffer.Size;
                Vector2 screenSize          = new Vector2(backbufferSize.Width, backbufferSize.Height);
                Vector2 logicalHeadMovement = Input.MouseDelta * screenSize;
                logicalHeadMovement.Y = -logicalHeadMovement.Y;

                float headRotationDelta = -logicalHeadMovement.X * MathUtil.Pi / 500.0f;
                Drone.UpdateHeadRotation(Drone.HeadRotation + headRotationDelta);

                if (Input.IsKeyPressed(Keys.Space) || Input.IsMouseButtonPressed(MouseButton.Left))
                {
                    Drone.Weapon?.TryShoot(null);
                }

                if (Input.IsKeyPressed(Keys.Escape))
                {
                    Input.UnlockMousePosition();
                }
            }
            else
            {
                if (Input.IsMouseButtonPressed(MouseButton.Left))
                {
                    Input.LockMousePosition(true);
                }
            }
        }
        private void ChaseUpdate()
        {
            Drone.Alerted = true;

            ChaseState chaseState = stateMachine.GetCurrentState <ChaseState>();

            if (chaseState == null)
            {
                throw new InvalidOperationException("ChaseUpdate can only be used with ChaseState");
            }

            if (chaseState.ChaseTarget == null)
            {
                // Stop chasing
                stateMachine.SwitchTo(PatrolState.Name);
                return;
            }

            IDestructible destructible = Utils.GetDestructible(chaseState.ChaseTarget);

            if (destructible == null)
            {
                throw new InvalidOperationException("ChaseTarget can only target IDestructibles");
            }
            if (destructible.IsDead)
            {
                // Stop chasing
                stateMachine.SwitchTo(PatrolState.Name);
                return;
            }

            // Check if still overlapping
            bool withinRange = false;

            foreach (var collision in alertZoneTrigger.Collisions)
            {
                var targetCollider = collision.ColliderA.Entity != alertZoneTrigger.Entity
                    ? collision.ColliderA
                    : collision.ColliderB;
                if (targetCollider == chaseState.ChaseColliderTarget)
                {
                    withinRange = true;
                    break;
                }
            }

            if (!withinRange)
            {
                // Stop chasing
                stateMachine.SwitchTo(PatrolState.Name);
                return;
            }

            // Recalculate path to player?
            Vector3 actualTargetPos = chaseState.ChaseTarget.Transform.WorldMatrix.TranslationVector;

            var source = Entity.Transform.WorldMatrix.TranslationVector;
            var target = actualTargetPos;

            source.Y = 1.5f;
            target.Y = 1.5f;
            Vector3 aimDir       = target - source;
            float   distToTarget = aimDir.Length();

            aimDir.Normalize();
            var playerTargeted = Drone.UpdateHeadRotation(aimDir);

            // Process move step
            if (chaseState.MoveOperation != null)
            {
                if (!chaseState.MoveOperation.MoveNext())
                {
                    chaseState.MoveOperation = null;
                }
            }

            bool hasLineOfSight = CheckLineOfSight(Entity, chaseState.ChaseColliderTarget);

            if (hasLineOfSight)
            {
                if (distToTarget < 6.0f)
                {
                    // No longer need to move, player is in line of sight, and drone is pretty close
                    chaseState.MoveOperation = null;
                    Drone.SetMovement(Vector3.Zero);
                }

                if (playerTargeted)
                {
                    // Shoot the player
                    Drone.Weapon?.TryShoot(chaseState.ChaseTarget);
                }
            }

            // Update path towards player when either not moving or
            //  the current path would end up too far from the player
            float targetDistance = (actualTargetPos - chaseState.CurrentChaseTargetPosition).Length();

            if (chaseState.MoveOperation == null || targetDistance > 1.0f)
            {
                chaseState.CurrentChaseTargetPosition = chaseState.ChaseTarget.Transform.WorldMatrix.TranslationVector;
                chaseState.MoveOperation = Move(chaseState.CurrentChaseTargetPosition);
            }
        }