/// <summary>
        /// Creates a temp node connected to the local
        /// </summary>
        /// <returns></returns>
        private WaypointNode MakeTempNode(bool stillOnCurrentPath)
        {
            WaypointNode tempNode = new WaypointNode(Position);

            if (!stillOnCurrentPath)
            {
                tempNode.ConnectedNodes = currentPlatform.ConnectedWaypoints;
            }
            else
            {
                tempNode.ConnectedNodes.Add(currentPath.Peek());
            }

            return(tempNode);
        }
        /// <summary>
        /// Select the next TravellingToNode State based on the node positions
        /// </summary>
        /// <param name="currentNode">The Node the character is at</param>
        /// <param name="nextNode">The next Node the character is going to</param>
        /// <returns>The TravellingToNode State</returns>
        private TravellingToNodeState SelectTravellingState(WaypointNode currentNode, WaypointNode nextNode)
        {
            //Reset jumped flag
            hasJumped = false;

            if (currentNode.ConnectedPlatform == nextNode.ConnectedPlatform)
            {
                return(TravellingToNodeState.SamePlatform);
            }
            else if (Math.Abs(nextNode.Position.Y - currentNode.Position.Y) > MinDistance)
            {
                return(TravellingToNodeState.DifferentPlatformVertical);
            }
            else
            {
                return(TravellingToNodeState.DifferentPlatformHorizontal);
            }
        }
        /// <summary>
        /// Draw whats needed this frame
        /// </summary>
        /// <param name="gameTime">Current Game Time</param>
        /// <param name="spriteBatch">Sprite Batch</param>
        public override void Draw(GameTime gameTime, SpriteBatch spriteBatch, GraphicsDevice graphicsDevice)
        {
            //Create waypoint texture
            if (waypointTex == null)
            {
                waypointTex = new Texture2D(graphicsDevice, 1, 1);
                waypointTex.SetData(new Color[] { Color.White });
            }

            if (CameraRef.IsInViewport(this))
            {
                spriteBatch.Draw(enemyTexture, Position, null, Color.White, Rotation.Z, Vector2.Zero, Scale, SpriteEffects.None, 0.0f);
            }
            else
            {
                //Draw an arrow pointing to our location
                Vector2 midpoint  = CameraRef.GetViewportMid();
                Vector2 direction = midpoint - Position;

                Vector2?offscreenAnchor = null;
                if (//Top of Viewport
                    (offscreenAnchor = PhysicsManager.FindLineIntersection(midpoint, Position, CameraRef.Position, CameraRef.Position + new Vector2(CameraRef.Viewport.X, 0))).HasValue ||
                    //Bottom of Viewport
                    (offscreenAnchor = PhysicsManager.FindLineIntersection(midpoint, Position, CameraRef.Position + new Vector2(0, CameraRef.Viewport.Y), CameraRef.Position + CameraRef.Viewport)).HasValue ||
                    //Right of Viewport
                    (offscreenAnchor = PhysicsManager.FindLineIntersection(midpoint, Position, CameraRef.Position + new Vector2(CameraRef.Viewport.X, 0), CameraRef.Position + CameraRef.Viewport)).HasValue ||
                    //Left of Viewport
                    (offscreenAnchor = PhysicsManager.FindLineIntersection(midpoint, Position, CameraRef.Position, CameraRef.Position + new Vector2(0, CameraRef.Viewport.Y))).HasValue)
                {
                    //Draw a line at the direction angle
                    Vector2 offscreenAngle = offscreenAnchor.Value - Position;
                    float   offscreenRot   = (float)Math.Atan2(offscreenAngle.Y, offscreenAngle.X);

                    offscreenAngle.Normalize();

                    //Draw indicator
                    spriteBatch.Draw(offscreenTex, offscreenAnchor.Value + (offscreenAngle * OffscreenIndicatorOffset), null, Color.White, offscreenRot, new Vector2(0, offscreenTex.Height / 2), new Vector2(1), Math.Abs(offscreenRot) > (Math.PI / 2) ? SpriteEffects.FlipVertically : SpriteEffects.None, 0.006f);
                }
            }

            //Debug Draw
            if (GameManager.DebugMode && currentPath != null && currentPath.Count > 0)
            {
                spriteBatch.DrawString(debugFont, CurrentMovingState.ToString(), new Vector2(Position.X, Position.Y - 25), Color.Red);

                //Draw his planned path in red
                WaypointNode prevNode = NextNode;
                spriteBatch.Draw(waypointTex, new Rectangle((int)prevNode.Position.X - 3, (int)prevNode.Position.Y - 3, 6, 6), Color.Yellow);
                foreach (WaypointNode node in currentPath)
                {
                    //Draw Waypoints
                    spriteBatch.Draw(waypointTex, new Rectangle((int)node.Position.X - 3, (int)node.Position.Y - 3, 6, 6), Color.Red);

                    Vector2 waypointLine = node.Position - prevNode.Position;
                    float   lineAngle    = (float)Math.Atan2(waypointLine.Y, waypointLine.X);

                    spriteBatch.Draw(waypointTex,
                                     new Rectangle((int)prevNode.Position.X, (int)prevNode.Position.Y, (int)waypointLine.Length(), 2),
                                     null,
                                     prevNode == NextNode ? Color.Yellow : Color.Red,
                                     lineAngle,
                                     new Vector2(0, 0),
                                     SpriteEffects.None,
                                     0);

                    prevNode = node;
                }
            }

            base.Draw(gameTime, spriteBatch, graphicsDevice);
        }
        /// <summary>
        /// Move Towards the next node based on the TravellingToNode State
        /// </summary>
        /// <param name="targetNode">The character's target node</param>
        private void MoveTowards(WaypointNode targetNode)
        {
            //Get distance data
            Vector2 deltaXY     = targetNode.Position - (new Vector2(Position.X + (BoxCollider.X / 2), Position.Y));
            Vector2 nodeDeltaXY = targetNode.Position - PreviousNode.Position;

            switch (CurrentMovingState)
            {
            case TravellingToNodeState.SamePlatform:
            {
                //Higher leniency means more velocity at the target node
                //Peek ahead to see whether we can afford to keep some momentum
                //Or whether we need to slow down completely
                float leniency = 1.5f;
                try
                {
                    WaypointNode peekNode = currentPath.Peek();
                    if (peekNode != null)
                    {
                        Vector2 peekDeltaXY = peekNode.Position - targetNode.Position;
                        if ((peekDeltaXY.X > 0 && deltaXY.X > 0) ||
                            (peekDeltaXY.X < 0 && deltaXY.X < 0))
                        {
                            leniency = 4.0f;
                        }
                    }
                }
                catch
                {
                    //Do Nothing
                }

                //Move in a straight line towards the target node, slowing down when near it
                double oppAcc           = CalculateAcceleration(new Vector2(-Force.X, Force.Y)).X;
                double timeToSlowdown   = -Velocity.X / (oppAcc * leniency);
                double distanceRequired = Math.Abs(Velocity.X * timeToSlowdown);

                //If we're within that distance
                if (Math.Abs(deltaXY.X) < distanceRequired)
                {
                    //Console.WriteLine("Slowing Down");
                    //Slowdown to a 0 vel
                    SlowdownHorizontal(deltaXY.X);
                }
                else
                {
                    //Move in direction
                    MoveHorizontal(deltaXY.X);
                }

                //Check if we're lost
                if (currentPlatform != targetNode.ConnectedPlatform)
                {
                    CurrentMovingState = TravellingToNodeState.Lost;
                }
                break;
            }

            case TravellingToNodeState.DifferentPlatformHorizontal:
            {
                //If we're below the target node, then we've fallen and are lost
                if ((currentPlatform.Position.Y < targetNode.ConnectedPlatform.Position.Y) ||
                    (hasJumped && OnGround && currentPlatform != targetNode.ConnectedPlatform))
                {
                    CurrentMovingState = TravellingToNodeState.Lost;
                    break;
                }
                else if (hasJumped && OnGround && currentPlatform == targetNode.ConnectedPlatform)
                {
                    //Change to Same-Platform traversal
                    WaypointNode tempNode = new WaypointNode(Position);
                    PreviousNode       = tempNode;
                    CurrentMovingState = TravellingToNodeState.SamePlatform;
                    break;
                }

                //Jump so we're in the air
                Jump();

                //Move in direction
                MoveHorizontal(deltaXY.X);
                break;
            }

            case TravellingToNodeState.DifferentPlatformVertical:
            {
                //If we've landed on the same platform as the node, switch to same platform
                if (currentPlatform == targetNode.ConnectedPlatform)
                {
                    CurrentState       = EnemyState.SelectingNode;
                    CurrentMovingState = TravellingToNodeState.SamePlatform;
                    break;
                }
                else if ((currentPlatform != targetNode.ConnectedPlatform &&
                          currentPlatform != PreviousNode.ConnectedPlatform) ||
                         (hasJumped && OnGround && currentPlatform != targetNode.ConnectedPlatform))
                {
                    //Lost
                    CurrentMovingState = TravellingToNodeState.Lost;
                    break;
                }

                //Calculate the wanted jump location
                float jumpXPos = targetNode.Position.X +
                                 ((Math.Abs(targetNode.Position.X - targetNode.ConnectedPlatform.Position.X) < Math.Abs(targetNode.Position.X - (targetNode.ConnectedPlatform.Position.X + targetNode.ConnectedPlatform.BoxCollider.X))) ? -MinNodeJumpX : MinNodeJumpX);
                float jumpPosDeltaX  = jumpXPos - (Position.X + (BoxCollider.X / 2));
                float prevNodeDeltaX = PreviousNode.Position.X - (Position.X + (BoxCollider.X / 2));

                //Are we on a moving platform?
                if (currentPlatform.PlatformType == Platform.PlatformTypes.DynamicMoving)
                {
                    //Move with the platform until we're at the jump
                    Vector2 platformVel = currentPlatform.Velocity;
                    //Navigate to the jumpPos
                    if (((nodeDeltaXY.X > MinNodeJumpX && nodeDeltaXY.X < MaxNodeJumpX && currentPlatform.Velocity.X < 0) ||
                         (nodeDeltaXY.X < MinNodeJumpX && nodeDeltaXY.X > MaxNodeJumpX && currentPlatform.Velocity.X > 0)) && !hasJumped)
                    {
                        //Needs to jump
                        Console.WriteLine($"Jump Delta: {jumpPosDeltaX} Node Delta: {nodeDeltaXY}");
                        Jump();
                    }
                    else if (!hasJumped)
                    {
                        //Hasnt jumped
                        Console.WriteLine($"Move with platform Delta: {prevNodeDeltaX} Node Delta: {nodeDeltaXY}");
                        MoveHorizontal(prevNodeDeltaX);
                    }
                    else
                    {
                        //Has jumped
                        Console.WriteLine($"In Air Delta: {deltaXY}");
                        Console.WriteLine(deltaXY);
                        MoveHorizontal(deltaXY.X);
                    }
                }
                //Are we jumping to a moving platform?
                else if (targetNode.ConnectedPlatform.PlatformType == Platform.PlatformTypes.DynamicMoving)
                {
                    //Wait until the platform is in range
                    if (((nodeDeltaXY.X > MinNodeJumpX && nodeDeltaXY.X < MaxNodeJumpX && targetNode.ConnectedPlatform.Velocity.X < 0) ||
                         (nodeDeltaXY.X < MinNodeJumpX && nodeDeltaXY.X > MaxNodeJumpX && targetNode.ConnectedPlatform.Velocity.X > 0)) && !hasJumped)
                    {
                        Jump();
                    }
                    else if (hasJumped)
                    {
                        MoveHorizontal(deltaXY.X);
                    }
                    else
                    {
                        MoveHorizontal(prevNodeDeltaX);
                    }
                }
                //Otherwise
                else
                {
                    //Navigate to the jumpPos
                    if (((jumpPosDeltaX > MinDistance && jumpPosDeltaX > 0) ||
                         (jumpPosDeltaX < -MinDistance && jumpPosDeltaX < 0)) && !hasJumped)
                    {
                        //Needs to jump
                        Jump();
                    }
                    else if (!hasJumped)
                    {
                        //Hasnt jumped
                        MoveHorizontal(jumpPosDeltaX);
                    }
                    else
                    {
                        //Has jumped
                        MoveHorizontal(deltaXY.X);
                    }
                }

                break;
            }

            case TravellingToNodeState.Lost:
            {
                //We're not where we should be...
                //Find a new path
                NextNode     = MakeTempNode(false);
                CurrentState = EnemyState.AtGoal;
                break;
            }
            }
        }
        /// <summary>
        /// Update Method for Enemy, Called once a frame
        /// </summary>
        /// <param name="gameTime">Current Game Time</param>
        public override void Update(GameTime gameTime)
        {
            //React based on current state
            switch (CurrentState)
            {
            case EnemyState.AtGoal:
            {
                //Select a new goal and populate the path
                WaypointNode goalNode = AI.GetNewGoalNode();
                if (goalNode != null)
                {
                    currentPath = AI.AStarSearch(NextNode, goalNode);
                }
                CurrentState = EnemyState.SelectingNode;

                break;
            }

            case EnemyState.SelectingNode:
            {
                //Select the next node in the list then begin travelling to it
                PreviousNode = NextNode;
                if (currentPath != null && currentPath.Count > 0)
                {
                    NextNode           = currentPath.Dequeue();
                    CurrentMovingState = SelectTravellingState(PreviousNode, NextNode);
                    CurrentState       = EnemyState.TravellingToNode;
                }
                else
                {
                    CurrentState = EnemyState.AtGoal;
                }

                break;
            }

            case EnemyState.TravellingToNode:
            {
                //Travel to the next node
                Vector2 dxy = NextNode.Position - Position;
                //Console.WriteLine($"Next Node: ({NextNode.Position.X}, {NextNode.Position.Y}) CurrentPos ({Position.X}, {Position.Y})");
                Rectangle tempRec = new Rectangle(Position.ToPoint() + new Point((int)BoxCollider.X / 4, 0), (BoxCollider / 2).ToPoint());
                if (tempRec.Contains(NextNode.Position) && OnGround)
                {
                    //Console.WriteLine("AT GOAL");
                    //If we have items left in the queue go to selecting node, if not we're at goal
                    CurrentState = currentPath.Count > 0 ? EnemyState.SelectingNode : EnemyState.AtGoal;
                }
                else
                {
                    MoveTowards(NextNode);
                }

                break;
            }
            }

            //Set OnGround to false
            OnGround = false;

            //Call RigidBody Update
            base.Update(gameTime);
        }
        /// <summary>
        /// Generate the Waypoints for the given platform row and connect them to the previous one at the given Y offset
        /// </summary>
        /// <param name="CurrentPlatformRow">An Array of the Current Plaform Row to generate Waypoints for</param>
        /// <param name="PreviousPlatformRow">An Array of the Previous Platform Row to connect the generated Waypoints to</param>
        /// <param name="waypointYOffset">The Y Offset to place the waypoints at</param>
        /// <returns>An array of WaypointNodes</returns>
        public WaypointNode[] GenerateWaypoints(Platform[] CurrentPlatformRow, Platform[] PreviousPlatformRow, float waypointYOffset)
        {
            //TODO:
            // Add safety incase either current row or previous row is null
            //Console.WriteLine("Waypoint");

            List <WaypointNode> waypointNodes = new List <WaypointNode>();

            float previousRowYDistance = PreviousPlatformRow[0].Position.Y - CurrentPlatformRow[0].Position.Y;

            //Add waypoints for the current platform row
            WaypointNode previousEdgeNode = new WaypointNode();

            for (int i = 0; i < CurrentPlatformRow.Length; i++)
            {
                //Generate a node at either side of each platform
                WaypointNode leftNode = new WaypointNode();
                leftNode.Position = new Vector2(CurrentPlatformRow[i].Position.X + WaypointEdgeBuffer,
                                                CurrentPlatformRow[i].Position.Y - waypointYOffset);
                leftNode.ConnectedPlatform = CurrentPlatformRow[i];

                WaypointNode rightNode = new WaypointNode();
                rightNode.Position = new Vector2(CurrentPlatformRow[i].Position.X + CurrentPlatformRow[i].Size.X - WaypointEdgeBuffer,
                                                 CurrentPlatformRow[i].Position.Y - waypointYOffset);
                rightNode.ConnectedPlatform = CurrentPlatformRow[i];

                //Connect them
                leftNode.ConnectedNodes.Add(rightNode);
                rightNode.ConnectedNodes.Add(leftNode);

                //Special case for a single platform on this row (Connect to the row below)
                if (CurrentPlatformRow.Length == 1)
                {
                    //Find closest waypoint on previous row and connect to it
                    WaypointNode closestToRightNode, closestToLeftNode;

                    //Find closest to Previous Edge Node
                    List <WaypointNode> sortedList = new List <WaypointNode>();
                    for (int j = 0; j < PreviousPlatformRow.Length; j++)
                    {
                        sortedList.AddRange(PreviousPlatformRow[j].ConnectedWaypoints);
                    }
                    //Sort by distance to right edge on X (to the right only)
                    sortedList.RemoveAll((n1) => n1.Position.X <= rightNode.Position.X);
                    if (sortedList.Count > 0)
                    {
                        sortedList.Sort((n1, n2) => (rightNode.Position.X - n1.Position.X).CompareTo(rightNode.Position.X - n2.Position.X));
                        closestToRightNode = sortedList[0];

                        if (Math.Abs((rightNode.Position - closestToRightNode.Position).Length()) < MaxConnectionLength)
                        {
                            rightNode.ConnectedNodes.Add(closestToRightNode);
                            closestToRightNode.ConnectedNodes.Add(rightNode);
                        }
                    }

                    //Find closest to left edge node
                    sortedList.Clear();
                    for (int j = 0; j < PreviousPlatformRow.Length; j++)
                    {
                        sortedList.AddRange(PreviousPlatformRow[j].ConnectedWaypoints);
                    }
                    //Sort by distance to previous edge on X (to the right only)
                    sortedList.RemoveAll((n1) => n1.Position.X >= leftNode.Position.X);
                    if (sortedList.Count > 0)
                    {
                        sortedList.Sort((n1, n2) => (n1.Position.X - leftNode.Position.X).CompareTo(n2.Position.X - leftNode.Position.X));
                        closestToLeftNode = sortedList[0];

                        if (Math.Abs((leftNode.Position - closestToLeftNode.Position).Length()) < MaxConnectionLength)
                        {
                            closestToLeftNode.ConnectedNodes.Add(leftNode);
                            leftNode.ConnectedNodes.Add(closestToLeftNode);
                        }
                    }
                }

                //Connect the platforms on each row together & to the row below it
                if (i > 0)
                {
                    previousEdgeNode.ConnectedNodes.Add(leftNode);
                    leftNode.ConnectedNodes.Add(previousEdgeNode);

                    //Add a waypoint in the middle of the two platforms on the row below to allow better jumping
                    Vector2 midPoint = (leftNode.Position + previousEdgeNode.Position) / 2;
                    midPoint = new Vector2(midPoint.X, midPoint.Y + previousRowYDistance);

                    //If it can find a platform at this point, put a waypoint there, if it can't then we asume it'll be able to
                    //connect via other means
                    try
                    {
                        Platform connectedPlatform = new List <Platform>(PreviousPlatformRow).Find((p) => midPoint.X >= p.Position.X && midPoint.X <= (p.Position.X + p.Size.X));

                        WaypointNode midNode = new WaypointNode();
                        midNode.Position          = midPoint;
                        midNode.ConnectedPlatform = connectedPlatform;

                        //Connect to all nearby nodes
                        midNode.ConnectedNodes.AddRange(connectedPlatform.ConnectedWaypoints);
                        for (int j = 0; j < connectedPlatform.ConnectedWaypoints.Count; j++)
                        {
                            connectedPlatform.ConnectedWaypoints[j].ConnectedNodes.Add(midNode);
                        }
                        midNode.ConnectedNodes.AddRange(new WaypointNode[] { previousEdgeNode, leftNode });
                        previousEdgeNode.ConnectedNodes.Add(midNode);
                        leftNode.ConnectedNodes.Add(midNode);
                        connectedPlatform.ConnectedWaypoints.Add(midNode);

                        //Add to our list
                        waypointNodes.Add(midNode);
                    }
                    catch
                    {
                        //Only do this if it's the first or last platform gap
                        //There's some weird behaviour if it tries to do it with the middle gaps
                        //When encountering certain platform compositions
                        //This is a bit of a hacky workaround

                        //With 4 platforms on the current row and 2 on the previous, the waypoint lines overlap
                        //the platforms, and not amount of intersection checks I am running can seem to detect this
                        //and remove it
                        //I suspect either due to the Monogame axis being inversed, or the scale of the drawing making
                        //it appear to overlap when it doesnt
                        //So in order to avoid this:

                        /*
                         *                 *
                         *  ____________            ____________
                         |__________|            |__________|
                         *
                         *                        *
                         * ___________                     ____________
                         * ___________|                    |___________
                         *
                         * It tries to connect the waypoints to the opposite top to allow you to jump up, however the waypoint line
                         * intersects with the platform, or it's so close it would ruin the AI but appears to intersect
                         * due to scale
                         */
                        //We do a hacky thing where it only makes paths up on the edges of the arena
                        if (i == 1 || i == CurrentPlatformRow.Length - 1)
                        {
                            //Find closest waypoint on previous row and connect to it
                            WaypointNode closestToPrevEdge, closestToLeftNode;

                            //Find closest to Previous Edge Node
                            List <WaypointNode> sortedList = new List <WaypointNode>();
                            for (int j = 0; j < PreviousPlatformRow.Length; j++)
                            {
                                sortedList.AddRange(PreviousPlatformRow[j].ConnectedWaypoints);
                            }
                            //Sort by distance to previous edge on X (to the right only)
                            sortedList.RemoveAll((n1) => n1.Position.X <= previousEdgeNode.ConnectedPlatform.Position.X + previousEdgeNode.ConnectedPlatform.BoxCollider.X);
                            if (sortedList.Count > 0)
                            {
                                sortedList.Sort((n1, n2) => (n1.Position.X - previousEdgeNode.Position.X).CompareTo(n2.Position.X - previousEdgeNode.Position.X));
                                closestToPrevEdge = sortedList[0];

                                previousEdgeNode.ConnectedNodes.Add(closestToPrevEdge);
                                closestToPrevEdge.ConnectedNodes.Add(previousEdgeNode);
                            }

                            //Find closest to left edge node
                            sortedList.Clear();
                            for (int j = 0; j < PreviousPlatformRow.Length; j++)
                            {
                                sortedList.AddRange(PreviousPlatformRow[j].ConnectedWaypoints);
                            }
                            //Sort by distance to previous edge on X (to the right only)
                            sortedList.RemoveAll((n1) => n1.Position.X >= leftNode.ConnectedPlatform.Position.X);
                            if (sortedList.Count > 0)
                            {
                                sortedList.Sort((n1, n2) => (leftNode.Position.X - n1.Position.X).CompareTo(leftNode.Position.X - n2.Position.X));
                                closestToLeftNode = sortedList[0];

                                //Connect to the visible waypoints on the area below
                                closestToLeftNode.ConnectedNodes.Add(leftNode);
                                leftNode.ConnectedNodes.Add(closestToLeftNode);
                            }
                        }
                    }
                }

                previousEdgeNode = rightNode;

                //Add to the waypoint nodes list & platform object
                waypointNodes.AddRange(new WaypointNode[] { leftNode, rightNode });
                CurrentPlatformRow[i].ConnectedWaypoints.AddRange(new WaypointNode[] { leftNode, rightNode });
            }

            return(waypointNodes.ToArray());
        }
Exemple #7
0
        /// <summary>
        /// Uses A* to compute the shortest path from the start node to the goal node
        /// </summary>
        /// <returns>An ordered list of the path taken to reach the goal node</returns>
        public Queue <WaypointNode> AStarSearch(WaypointNode startNode, WaypointNode endNode)
        {
            List <WaypointNode> openList   = new List <WaypointNode>();
            List <WaypointNode> closedList = new List <WaypointNode>();

            //Make sure we have a goal
            if (endNode == null)
            {
                //Error - No Goal
                return(null);
            }

            //Add the start node to the open list
            openList.Add(startNode);
            WaypointNode currentNode = startNode;

            while (openList.Count > 0)
            {
                //Sort based on lowest heuristic
                openList.Sort((n1, n2) => (n1.H + n1.G).CompareTo((n2.H + n2.G)));

                //Get the next node
                currentNode = openList[0];
                closedList.Add(currentNode);
                openList.RemoveAt(0);

                //Check if we're at the goal node
                if (currentNode == endNode)
                {
                    //Break out of search and trace back
                    break;
                }

                //For each connected node
                for (int i = 0; i < currentNode.ConnectedNodes.Count; i++)
                {
                    //If it's on the closed list
                    if (closedList.Contains(currentNode.ConnectedNodes[i]))
                    {
                        //Ignore it
                        continue;
                    }
                    //If it's already in the open list, check to see if it's a better path
                    //and reassign the parent node
                    //If not, add it and assign parent node
                    else if (openList.Contains(currentNode.ConnectedNodes[i]))
                    {
                        float curF = currentNode.ConnectedNodes[i].ParentNode.G + currentNode.ConnectedNodes[i].ParentNode.H;
                        //If our F is less than it's current F, then we swap the parents over
                        if (currentNode.G + currentNode.H < curF)
                        {
                            int index = openList.FindIndex((n1) => n1 == currentNode.ConnectedNodes[i]);
                            openList[index].ParentNode = currentNode;
                            openList[index].CalculateG();
                        }
                        //Otherwise we ignore it
                    }
                    else
                    {
                        //Calculate Heuristics and add to open list
                        currentNode.ConnectedNodes[i].ParentNode = currentNode;
                        currentNode.ConnectedNodes[i].CalculateG();
                        currentNode.ConnectedNodes[i].CalculateH(endNode.Position);

                        openList.Add(currentNode.ConnectedNodes[i]);
                    }
                }
            }

            //If we found the end node
            if (endNode.ParentNode != null)
            {
                Queue <WaypointNode> path = new Queue <WaypointNode>();
                //Trace back through the end node to the start node
                WaypointNode pathNode = endNode;
                while (pathNode != null && pathNode != startNode)
                {
                    path.Enqueue(pathNode);
                    pathNode = pathNode.ParentNode;
                }
                //Reverse path & return
                path = new Queue <WaypointNode>(path.Reverse());
                return(path);
            }
            else
            {
                //Couldnt find a path
                return(null);
            }
        }