コード例 #1
0
 private void NextNode(bool checkDoors)
 {
     if (checkDoors)
     {
         CheckDoorsInPath();
     }
     currentPath.SkipToNextNode();
 }
コード例 #2
0
        private Vector2 DiffToCurrentNode()
        {
            if (currentPath == null || currentPath.Unreachable)
            {
                return(Vector2.Zero);
            }

            if (currentPath.Finished)
            {
                Vector2 pos2 = host.SimPosition;
                if (character != null && character.Submarine == null &&
                    CurrentPath.Nodes.Count > 0 && CurrentPath.Nodes.Last().Submarine != null)
                {
                    pos2 -= CurrentPath.Nodes.Last().Submarine.SimPosition;
                }
                return(currentTarget - pos2);
            }

            if (canOpenDoors && !character.LockHands && buttonPressCooldown <= 0.0f)
            {
                CheckDoorsInPath();
            }

            Vector2 pos = host.SimPosition;

            if (character != null && currentPath.CurrentNode != null)
            {
                if (CurrentPath.CurrentNode.Submarine != null)
                {
                    if (character.Submarine == null)
                    {
                        pos -= CurrentPath.CurrentNode.Submarine.SimPosition;
                    }
                    else if (character.Submarine != currentPath.CurrentNode.Submarine)
                    {
                        pos -= FarseerPhysics.ConvertUnits.ToSimUnits(currentPath.CurrentNode.Submarine.Position - character.Submarine.Position);
                    }
                }
            }

            bool isDiving = character.AnimController.InWater && character.AnimController.HeadInWater;

            //only humanoids can climb ladders
            if (!isDiving && character.AnimController is HumanoidAnimController && IsNextLadderSameAsCurrent)
            {
                if (character.SelectedConstruction != currentPath.CurrentNode.Ladders.Item &&
                    currentPath.CurrentNode.Ladders.Item.IsInsideTrigger(character.WorldPosition))
                {
                    currentPath.CurrentNode.Ladders.Item.TryInteract(character, false, true);
                }
            }

            var collider = character.AnimController.Collider;

            if (character.IsClimbing && !isDiving)
            {
                Vector2 diff = currentPath.CurrentNode.SimPosition - pos;
                bool    nextLadderSameAsCurrent = IsNextLadderSameAsCurrent;

                if (nextLadderSameAsCurrent)
                {
                    //climbing ladders -> don't move horizontally
                    diff.X = 0.0f;
                }

                //at the same height as the waypoint
                if (Math.Abs(collider.SimPosition.Y - currentPath.CurrentNode.SimPosition.Y) < (collider.height / 2 + collider.radius) * 1.25f)
                {
                    float heightFromFloor = character.AnimController.GetColliderBottom().Y - character.AnimController.FloorY;
                    if (heightFromFloor <= 0.0f)
                    {
                        diff.Y = Math.Max(diff.Y, 1.0f);
                    }

                    bool aboveFloor = heightFromFloor > 0 && heightFromFloor < collider.height * 1.5f;
                    if (aboveFloor || IsNextNodeLadder)
                    {
                        if (!nextLadderSameAsCurrent)
                        {
                            character.AnimController.Anim = AnimController.Animation.None;
                        }
                        currentPath.SkipToNextNode();
                    }
                }
                else if (nextLadderSameAsCurrent)
                {
                    //if the current node is below the character and the next one is above (or vice versa)
                    //and both are on ladders, we can skip directly to the next one
                    //e.g. no point in going down to reach the starting point of a path when we could go directly to the one above
                    if (Math.Sign(currentPath.CurrentNode.WorldPosition.Y - character.WorldPosition.Y) != Math.Sign(currentPath.NextNode.WorldPosition.Y - character.WorldPosition.Y))
                    {
                        currentPath.SkipToNextNode();
                    }
                }
                return(diff);
            }
            else if (character.AnimController.InWater)
            {
                // If the character is underwater, we don't need the ladders anymore
                if (character.IsClimbing && isDiving)
                {
                    character.AnimController.Anim  = AnimController.Animation.None;
                    character.SelectedConstruction = null;
                }
                float multiplier = MathHelper.Lerp(1, 10, MathHelper.Clamp(collider.LinearVelocity.Length() / 10, 0, 1));
                if (Vector2.DistanceSquared(pos, currentPath.CurrentNode.SimPosition) < MathUtils.Pow(collider.radius * 2 * multiplier, 2))
                {
                    currentPath.SkipToNextNode();
                }
            }
            else
            {
                Vector2 colliderBottom = character.AnimController.GetColliderBottom();
                Vector2 colliderSize   = collider.GetSize();
                Vector2 velocity       = collider.LinearVelocity;
                // Cannot use the head position, because not all characters have head or it can be below the total height of the character
                float characterHeight    = colliderSize.Y + character.AnimController.ColliderHeightFromFloor;
                float horizontalDistance = Math.Abs(collider.SimPosition.X - currentPath.CurrentNode.SimPosition.X);
                bool  isAboveFeet        = currentPath.CurrentNode.SimPosition.Y > colliderBottom.Y;
                bool  isNotTooHigh       = currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y + characterHeight;
                float margin             = MathHelper.Lerp(1, 10, MathHelper.Clamp(Math.Abs(velocity.X) / 10, 0, 1));
                float targetDistance     = collider.radius * margin;
                if (horizontalDistance < targetDistance && isAboveFeet && isNotTooHigh)
                {
                    currentPath.SkipToNextNode();
                }
            }

            if (currentPath.CurrentNode == null)
            {
                return(Vector2.Zero);
            }

            return(currentPath.CurrentNode.SimPosition - pos);
        }
コード例 #3
0
        private Vector2 DiffToCurrentNode()
        {
            if (currentPath == null || currentPath.Finished || currentPath.Unreachable)
            {
                return(Vector2.Zero);
            }

            if (currentPath.Finished)
            {
                Vector2 pos2 = host.SimPosition;
                if (character != null && character.Submarine == null && CurrentPath.Nodes.Last().Submarine != null)
                {
                    //todo: take multiple subs into account
                    pos2 -= CurrentPath.Nodes.Last().Submarine.SimPosition;
                }
                return(currentTarget - pos2);
            }

            if (canOpenDoors && !character.LockHands)
            {
                CheckDoorsInPath();
            }

            Vector2 pos = host.SimPosition;

            if (character != null && currentPath.CurrentNode != null)
            {
                if (CurrentPath.CurrentNode.Submarine != null)
                {
                    if (character.Submarine == null)
                    {
                        pos -= CurrentPath.CurrentNode.Submarine.SimPosition;
                    }
                    else if (character.Submarine != currentPath.CurrentNode.Submarine)
                    {
                        pos -= FarseerPhysics.ConvertUnits.ToSimUnits(currentPath.CurrentNode.Submarine.Position - character.Submarine.Position);
                    }
                }
            }

            if (currentPath.CurrentNode != null && currentPath.CurrentNode.Ladders != null)
            {
                if (character.SelectedConstruction != currentPath.CurrentNode.Ladders.Item && currentPath.CurrentNode.Ladders.Item.IsInsideTrigger(character.WorldPosition))
                {
                    currentPath.CurrentNode.Ladders.Item.TryInteract(character, false, true);
                }
            }

            var     collider       = character.AnimController.Collider;
            Vector2 colliderBottom = character.AnimController.GetColliderBottom();

            if (Math.Abs(collider.SimPosition.X - currentPath.CurrentNode.SimPosition.X) < collider.radius * 2 &&
                currentPath.CurrentNode.SimPosition.Y > colliderBottom.Y &&
                currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y + 1.5f)
            {
                currentPath.SkipToNextNode();
            }

            if (currentPath.CurrentNode == null)
            {
                return(Vector2.Zero);
            }

            if (character.AnimController.Anim == AnimController.Animation.Climbing)
            {
                Vector2 diff = currentPath.CurrentNode.SimPosition - pos;

                if (currentPath.CurrentNode.Ladders != null)
                {
                    //climbing ladders -> don't move horizontally
                    diff.X = 0.0f;

                    //at the same height as the waypoint
                    if (Math.Abs(collider.SimPosition.Y - currentPath.CurrentNode.SimPosition.Y) < collider.height / 2 + collider.radius)
                    {
                        float heightFromFloor = character.AnimController.GetColliderBottom().Y - character.AnimController.FloorY;

                        //we can safely skip to the next waypoint if the character is at a safe height above the floor,
                        //or if the next waypoint in the path is also on ladders
                        if ((heightFromFloor > 0.0f && heightFromFloor < collider.height) ||
                            (currentPath.NextNode != null && currentPath.NextNode.Ladders != null))
                        {
                            currentPath.SkipToNextNode();
                        }
                    }
                }

                character.AnimController.IgnorePlatforms = false;
                return(diff);
            }

            return(currentPath.CurrentNode.SimPosition - pos);
        }
コード例 #4
0
        private Vector2 DiffToCurrentNode()
        {
            if (currentPath == null || currentPath.Unreachable)
            {
                return(Vector2.Zero);
            }
            if (currentPath.Finished)
            {
                Vector2 pos2 = host.SimPosition;
                if (character != null && character.Submarine == null &&
                    CurrentPath.Nodes.Count > 0 && CurrentPath.Nodes.Last().Submarine != null)
                {
                    pos2 -= CurrentPath.Nodes.Last().Submarine.SimPosition;
                }
                return(currentTarget - pos2);
            }
            if (canOpenDoors && !character.LockHands && buttonPressCooldown <= 0.0f)
            {
                CheckDoorsInPath();
            }
            Vector2 pos = host.SimPosition;

            if (character != null && currentPath.CurrentNode != null)
            {
                if (CurrentPath.CurrentNode.Submarine != null)
                {
                    if (character.Submarine == null)
                    {
                        pos -= CurrentPath.CurrentNode.Submarine.SimPosition;
                    }
                    else if (character.Submarine != currentPath.CurrentNode.Submarine)
                    {
                        pos -= ConvertUnits.ToSimUnits(currentPath.CurrentNode.Submarine.Position - character.Submarine.Position);
                    }
                }
            }
            bool isDiving = character.AnimController.InWater && character.AnimController.HeadInWater;
            // Only humanoids can climb ladders
            bool canClimb = character.AnimController is HumanoidAnimController;
            var  ladders  = GetNextLadder();

            if (canClimb && !isDiving && ladders != null && character.SelectedConstruction != ladders.Item)
            {
                if (IsNextNodeLadder || currentPath.CurrentIndex == currentPath.Nodes.Count - 1)
                {
                    if (character.CanInteractWith(ladders.Item))
                    {
                        ladders.Item.TryInteract(character, false, true);
                    }
                    else
                    {
                        // Cannot interact with the current (or next) ladder,
                        // Try to select the previous ladder, unless it's already selected, unless the previous ladder is not adjacent to the current ladder.
                        // The intention of this code is to prevent the bots from dropping from the "double ladders".
                        var previousLadders = currentPath.PrevNode?.Ladders;
                        if (previousLadders != null && previousLadders != ladders && character.SelectedConstruction != previousLadders.Item &&
                            character.CanInteractWith(previousLadders.Item) && Math.Abs(previousLadders.Item.WorldPosition.X - ladders.Item.WorldPosition.X) < 5)
                        {
                            previousLadders.Item.TryInteract(character, false, true);
                        }
                    }
                }
                else if (!IsNextLadderSameAsCurrent && character.SelectedConstruction?.GetComponent <Ladder>() != null && character.CanInteractWith(ladders.Item))
                {
                    ladders.Item.TryInteract(character, false, true);
                }
            }
            var collider = character.AnimController.Collider;

            if (character.IsClimbing && !isDiving)
            {
                Vector2 diff       = currentPath.CurrentNode.SimPosition - pos;
                Ladder  nextLadder = GetNextLadder();
                bool    nextLadderSameAsCurrent = IsNextLadderSameAsCurrent;
                if (nextLadderSameAsCurrent)
                {
                    //climbing ladders -> don't move horizontally
                    diff.X = 0.0f;
                }
                //at the same height as the waypoint
                if (Math.Abs(collider.SimPosition.Y - currentPath.CurrentNode.SimPosition.Y) < (collider.height / 2 + collider.radius) * 1.25f)
                {
                    float heightFromFloor = character.AnimController.GetColliderBottom().Y - character.AnimController.FloorY;
                    if (heightFromFloor <= 0.0f)
                    {
                        diff.Y = Math.Max(diff.Y, 1.0f);
                    }
                    // We need some margin, because if a hatch has closed, it's possible that the height from floor is slightly negative.
                    float margin       = 0.1f;
                    bool  isAboveFloor = heightFromFloor > -margin && heightFromFloor < collider.height * 1.5f;
                    // If the next waypoint is horizontally far, we don't want to keep holding the ladders
                    if (isAboveFloor && (nextLadder == null || Math.Abs(currentPath.CurrentNode.WorldPosition.X - currentPath.NextNode.WorldPosition.X) > 50))
                    {
                        character.AnimController.Anim  = AnimController.Animation.None;
                        character.SelectedConstruction = null;
                    }
                    else if (nextLadder != null && !nextLadderSameAsCurrent)
                    {
                        // Try to change the ladder (hatches between two submarines)
                        if (character.SelectedConstruction != nextLadder.Item && nextLadder.Item.IsInsideTrigger(character.WorldPosition))
                        {
                            nextLadder.Item.TryInteract(character, false, true);
                        }
                    }
                    if (nextLadder != null || isAboveFloor)
                    {
                        currentPath.SkipToNextNode();
                    }
                }
                else if (nextLadder != null)
                {
                    //if the current node is below the character and the next one is above (or vice versa)
                    //and both are on ladders, we can skip directly to the next one
                    //e.g. no point in going down to reach the starting point of a path when we could go directly to the one above
                    if (Math.Sign(currentPath.CurrentNode.WorldPosition.Y - character.WorldPosition.Y) != Math.Sign(currentPath.NextNode.WorldPosition.Y - character.WorldPosition.Y))
                    {
                        currentPath.SkipToNextNode();
                    }
                }
                return(diff);
            }
            else if (!canClimb || character.AnimController.InWater)
            {
                // If the character is underwater, we don't need the ladders anymore
                if (character.IsClimbing && isDiving)
                {
                    character.AnimController.Anim  = AnimController.Animation.None;
                    character.SelectedConstruction = null;
                }
                var  door          = currentPath.CurrentNode.ConnectedDoor;
                bool blockedByDoor = door != null && !door.IsOpen && !door.IsBroken;
                if (!blockedByDoor)
                {
                    float multiplier         = MathHelper.Lerp(1, 10, MathHelper.Clamp(collider.LinearVelocity.Length() / 10, 0, 1));
                    float targetDistance     = collider.GetSize().X *multiplier;
                    float horizontalDistance = Math.Abs(character.WorldPosition.X - currentPath.CurrentNode.WorldPosition.X);
                    float verticalDistance   = Math.Abs(character.WorldPosition.Y - currentPath.CurrentNode.WorldPosition.Y);
                    if (character.CurrentHull != currentPath.CurrentNode.CurrentHull)
                    {
                        verticalDistance *= 2;
                    }
                    float distance = horizontalDistance + verticalDistance;
                    if (ConvertUnits.ToSimUnits(distance) < targetDistance)
                    {
                        currentPath.SkipToNextNode();
                    }
                }
            }
            else if (!IsNextLadderSameAsCurrent)
            {
                // Walking horizontally
                Vector2 colliderBottom = character.AnimController.GetColliderBottom();
                Vector2 colliderSize   = collider.GetSize();
                Vector2 velocity       = collider.LinearVelocity;
                // If the character is smaller than this, it would fail to use the waypoint nodes because they are always too high.
                float minHeight = 1;
                // Cannot use the head position, because not all characters have head or it can be below the total height of the character
                float characterHeight    = Math.Max(colliderSize.Y + character.AnimController.ColliderHeightFromFloor, minHeight);
                float horizontalDistance = Math.Abs(collider.SimPosition.X - currentPath.CurrentNode.SimPosition.X);
                bool  isAboveFeet        = currentPath.CurrentNode.SimPosition.Y > colliderBottom.Y;
                bool  isNotTooHigh       = currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y + characterHeight;
                var   door           = currentPath.CurrentNode.ConnectedDoor;
                bool  blockedByDoor  = door != null && !door.IsOpen && !door.IsBroken;
                float margin         = MathHelper.Lerp(1, 10, MathHelper.Clamp(Math.Abs(velocity.X) / 10, 0, 1));
                float targetDistance = collider.radius * margin;
                if (horizontalDistance < targetDistance && isAboveFeet && isNotTooHigh && !blockedByDoor)
                {
                    currentPath.SkipToNextNode();
                }
            }
            if (currentPath.CurrentNode == null)
            {
                return(Vector2.Zero);
            }
            return(currentPath.CurrentNode.SimPosition - pos);
        }