/// <summary>
        /// Check if this GraphNode can be passed; eg. is it solid of empty?
        /// </summary>
        /// <param name="startingNode">The node we are travelling from.</param>
        /// <returns>True if if the node can be travelled to.</returns>
        public override Boolean IsPassable(GraphNode startingNode)
        {
            // If this GraphNode is not storing a tile, or that Tile is not empty, thats
            // an instant fail.
            if (!IsEmpty())
            {
                return false;
            }

            // We should not have mismatch GraphNode objects, so pData should be Level.Tile in this case.
            Level.Tile tile = startingNode.pData as Level.Tile;

            // Loop through all adjacent tiles to figure out which direction we are travelling in.
            // We need that data in order to determine if this is a legal diagonal move.
            for (Int32 i = 0; i < tile.mAdjecentTiles.Length; i++)
            {
                if (mTile == tile.mAdjecentTiles[i])
                {
                    if (Level.IsAttemptingInvalidDiagonalMove((Level.Tile.AdjacentTileDir)i, tile))
                    {
                        return false;
                    }
                    else
                    {
                        // No need to continue searching.
                        break;
                    }
                }
            }

            return true;
        }
示例#2
0
            /// <summary>
            /// When finished using a Node which was retrieved from GetNode, pass it back to
            /// this function for clean up.
            /// </summary>
            /// <param name="node"></param>
            public void RecycleNode(GraphNode node)
            {
                node.Reset();
#if DEBUG
                node.mInUse = false;
#endif // DEBUG
                mUnusedNavMeshTileGraphNodes.Enqueue(node as NavMeshTileGraphNode);
            }
示例#3
0
 /// <summary>
 /// These nodes get used over and over again, so we need to make sure they 
 /// get completely reset between uses.
 /// </summary>
 public void Reset()
 {
     mGraphNode = null;
     mPrevious = null;
     mCostFromStart = 0;
     mCostToDestination = 0;
     mReached = false;
     mPathSolved = false;
 }
示例#4
0
        /// <summary>
        /// Renders a single GraphNode and optionally links to all it's neighbours. Derived Graph classes should try
        /// to use this function even if overriding DebugDraw so that there is a consistent look to Graph objects.
        /// </summary>
        /// <param name="node">The GraphNode to render.</param>
        /// <param name="showLinks">True to draw links to neighbouring GraphNode objects.</param>
        protected virtual void DrawNode(GraphNode node, Boolean showLinks)
        {                    
            // Draw the node a circle.
            DebugShapeDisplay.pInstance.AddCircle(node.pPosition, 4.0f, Color.DarkRed);

            // If requested show the links between this node and all his neighbours.
            if (showLinks)
            {
                for (Int32 j = 0; j < node.pNeighbours.Count; j++)
                {
                    Color costColor = Color.Lerp(Color.White, Color.Red, (node.pNeighbours[j].mCostToTravel - 8.0f) / (3.0f * 11.134f));
                    DebugShapeDisplay.pInstance.AddSegment(node.pPosition, node.pNeighbours[j].mGraphNode.pPosition, costColor);
                }
            }
        }
示例#5
0
        /// <summary>
        /// Doesn't actually do anthing different in Release, but in Debug it does some checks for 
        /// duplicate entries. Doing this for all Graph objects would be too expensive even for testing.
        /// </summary>
        /// <param name="node">The node to add.</param>
        public override void AddNode(GraphNode node)
        {
            /*
            for(Int32 i = 0; i < pNodes.Count; i++)
            {
                if (pNodes[i].pPosition == node.pPosition)
                {
                    //System.Diagnostics.Debug.Assert(false, "Attempting to add GraphNode at dupe position.");
                }

                if (pNodes.Contains(node))
                {
                    //System.Diagnostics.Debug.Assert(false, "Attempting to add Dupe GraphNode.");
                }
            }
            */

            base.AddNode(node);
        }
示例#6
0
        /// <summary>
        /// Update where this Planner is travelling from. The position is used to look up a tile at that
        /// position in the world.
        /// </summary>
        /// <param name="source">The position in the world that the planner will start at.</param>
        public Boolean SetSource(GraphNode source)
        {
            //System.Diagnostics.Debug.Assert(source != mEnd || source == null, "Source and Destination are the same.");

            //HPAStar.NavMesh.DebugCheckNode(source);

            if (mStart != source)
            {
                mStart = source;
                mPathInvalidated = true;
                mSolved = false;

                return true;
            }

            return false;
        }
示例#7
0
        /// <summary>
        /// Similar to SetDestination, except in this case the existing path is not invalidated. Instead
        /// the path searching continues as if the supplied destination were the original destination.
        /// </summary>
        /// <param name="destination">The node to try and reach.</param>
        /// <returns></returns>
        public Boolean ExtendDestination(GraphNode destination)
        {
            if (mEnd != destination)
            {
                // Make sure that we are not trying to extend the destination
                // to a Node that has already be Closed. If that is the case
                // then the path needs to be regenerated with fresh data.
                for (Int32 i = 0; i < mClosedNodes.Count; i++)
                {
                    if (mClosedNodes[i].pGraphNode == destination)
                    {
                        //DebugMessageDisplay.pInstance.AddConstantMessage("Extending with closed node.");
                        
                        return SetDestination(destination);
                    }
                }
                
                mEnd = destination;

                // If the path was previously solved, it is not any longer.
                mSolved = false;

                // If the path was already solved, it needs to be told otherwise.
                mBestPathEnd.pPathSolved = false;

                return true;
            }

            return false;
        }
示例#8
0
        /// <summary>
        /// Checks if a Node and it's neighbours are erronously flagged as being not in use or contain
        /// null data.
        /// </summary>
        /// <param name="node">The node to check. The node assumed to be in use.</param>
        static public void DebugCheckNode(GraphNode node)
        {
            if (node is NavMeshTileGraphNode)
            {
                System.Diagnostics.Debug.Assert(node.mInUse, "Node being used but flag as not in use.");
                System.Diagnostics.Debug.Assert(node.pData != null, "pData is null.");

                for (Int32 j = 0; j < node.pNeighbours.Count; j++)
                {
                    System.Diagnostics.Debug.Assert(node.pNeighbours[j].mGraphNode.mInUse, "Node being used but flag as not in use.");
                    System.Diagnostics.Debug.Assert(node.pNeighbours[j].mGraphNode.pData != null, "pData is null.");
                }
            }
        }
示例#9
0
        /// <summary>
        /// Take two GraphNode objects and remove any link they have as Neighbour.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        public void UnlinkGraphNodes(GraphNode a, GraphNode b)
        {
            a.RemoveNeighbour(b);
            b.RemoveNeighbour(a);

            //if (a != null)
            //{
                //DebugWalkGraphForErrors(a as NavMeshTileGraphNode);
            //}

            //DebugCheckNode(a);
            //DebugCheckNode(b);
        }
示例#10
0
        /// <summary>
        /// Removes a Neighbour by looking at the GraphNode stored in each one.
        /// </summary>
        /// <param name="neighbour">The GraphNode in the Neighbour that should be removed.</param>
        public virtual void RemoveNeighbour(GraphNode neighbour)
        {
            for (Int32 i = 0; i < mNeighbours.Count; i++)
            {
                if (mNeighbours[i].mGraphNode == neighbour)
                {
                    //HPAStar.NavMesh.DebugCheckNode(mNeighbours[i].mGraphNode);

                    mNeighbours[i].Reset();
                    
                    // Put this Neighbour back into the Queue so others can reuse it.
                    mUnusedNeighbours.Enqueue(mNeighbours[i]);

                    mNeighbours.RemoveAt(i);

                    // Should be no dupes so return after finding one.
                    return;
                }
            }
        }
示例#11
0
        /// <summary>
        /// Adds a neighbour to this GraphNode.
        /// </summary>
        /// <param name="node">The neighbouring GraphNode.</param>
        /// <param name="cost">
        /// The cost to travel from this GraphNode to <paramref name="node"/>. If not supplied the cost will 
        /// be the distance between the two GraphNode objects.
        /// </param>
        public virtual void AddNeighbour(GraphNode node, Single cost)
        {
            //HPAStar.NavMesh.DebugCheckNode(node);

            // Create a new neighbour to wrap the node passed in.
            Neighbour temp = mUnusedNeighbours.Dequeue();

            // Put it back into a default state.
            temp.Reset();

            temp.mGraphNode = node;

            if (cost >= 0)
            {
                temp.mCostToTravel = cost;
            }
            else
            {
                // This assumes that nodes never move.
                temp.mCostToTravel = Vector2.Distance(node.pPosition, pPosition);
            }

            System.Diagnostics.Debug.Assert(node.pData != null, "Uninitialized node set as neighbour");

            mNeighbours.Add(temp);
        }
示例#12
0
 /// <summary>
 /// Adds a neighbour to this GraphNode.
 /// </summary>
 /// <param name="node">The neighbouring GraphNode.</param>
 /// <param name="cost">
 /// The cost to travel from this GraphNode to <paramref name="node"/>. If not supplied the cost will 
 /// be the distance between the two GraphNode objects.
 /// </param>
 public virtual void AddNeighbour(GraphNode node)
 {
     AddNeighbour(node, -1.0f);
 }
示例#13
0
 /// <summary>
 /// Removes a GraphNode from the Graph.
 /// </summary>
 /// <param name="node"></param>
 public virtual void RemoveNode(GraphNode node)
 {
     mNodes.Remove(node);
 }
示例#14
0
 /// <summary>
 /// Adds a GraphNode to the Graph.
 /// </summary>
 /// <param name="node">The node to add.</param>
 public virtual void AddNode(GraphNode node)
 {
     mNodes.Add(node);
 }
示例#15
0
        /// <summary>
        /// Clear out the destination that the planner is trying to reach. This doubles as a way
        /// to stop the planner from trying to advance.
        /// </summary>
        public void ClearDestination()
        {
            mEnd = null;
            mSolved = false;

            // Release the Nodes. We don't need them anymore. If a new destination
            // is set, we will need to start from scratch anyway.
            ClearNodeLists();
        }
示例#16
0
        /// <summary>
        /// Helper method for checking if any of the Neighbours of this GraphNode contain a 
        /// supplied GraphNode.
        /// </summary>
        /// <param name="neighbour"></param>
        /// <returns></returns>
        public virtual Boolean HasNeighbour(GraphNode neighbour)
        {
            for (Int32 i = 0; i < mNeighbours.Count; i++)
            {
                if (mNeighbours[i].mGraphNode == neighbour)
                {
                    return true;
                }
            }

            return false;
        }
示例#17
0
 /// <summary>
 /// Return the planner to its original state.
 /// </summary>
 public void Reset()
 {
     mStart = null;
     ClearDestination();
     ClearNodeLists();
 }
示例#18
0
 /// <summary>
 /// Check if this GraphNode can be passed; eg. is it solid of empty?
 /// </summary>
 /// <param name="startingNode">The node we are travelling from.</param>
 /// <returns>True if if the node can be travelled to.</returns>
 public abstract Boolean IsPassable(GraphNode startingNode);
示例#19
0
        /// <summary>
        /// Links two GraphNode objects as Neighbour. Does the slightly expensive task of calculating actual
        /// A* path between the two, and caches that value as the cost between the two.
        /// </summary>
        /// <param name="a">A node to link to <paramref name="b"/>.</param>
        /// <param name="b">A node to link to <paramref name="a"/>.</param>
        /// <param name="cluster">The cluster containing both nodes.</param>
        private void LinkGraphNodes(GraphNode a, GraphNode b, Cluster cluster)
        {
            Boolean oneWay = false;

            mPlanner.Reset();
            mPlanner.SetSource((a.pData as Level.Tile).mGraphNode);
            mPlanner.SetDestination((b.pData as Level.Tile).mGraphNode);

            // Do a standard A* search with the adde constraint of staying within the 
            // bounds of this cluster.
            Planner.Result result = mPlanner.PlanPath(cluster.pBounds, false);

            // Keep searching unti we either fail or succeed.
            while(result == Planner.Result.InProgress)
            {
                result = mPlanner.PlanPath(cluster.pBounds, false);
            }

            // Only connect the nodes if they can be reached from one another within the same cluster.
            if (result == Planner.Result.Solved)
            {
                PathNode path = mPlanner.pCurrentBest;

                // Link the two neightbours.
                a.AddNeighbour(b, path.pFinalCost);
                if (!oneWay)
                {
                    b.AddNeighbour(a, path.pFinalCost);
                }
            }

            mPlanner.ClearDestination();

            //if (a != null)
            //{
                //DebugWalkGraphForErrors(a as NavMeshTileGraphNode);
            //}

            //DebugCheckNode(a);
            //DebugCheckNode(b);
        }
示例#20
0
 /// <summary>
 /// Put this object into a default state.
 /// </summary>
 public void Reset()
 {
     mGraphNode = null;
     mCostToTravel = 0;
 }
示例#21
0
        /// <summary>
        /// Helper function for creating a Node for an entrace but also checking that it hasn't already been
        /// created, and if it has, just using that one instead to avoid multiple Nodes on top of the same
        /// tile.
        /// </summary>
        /// <param name="cluster">The custer which this node lives in.</param>
        /// <param name="tile">The tile which this node wraps.</param>
        /// <param name="node">
        /// If a node already exists over <paramref name="tile"/> this will be that GraphNode. If not it will 
        /// be a newly created GraphNode.
        /// </param>
        /// <returns>True if a new GraphNode was created.</returns>
        private Boolean CreateEntraceNode(Cluster cluster, Level.Tile tile, out GraphNode node)
        {
            Boolean created = false;

            // First see if this Tile is already managed by this cluster. If it is, it will return us
            // the node which contains it.
            node = cluster.GetNodeContaining(tile);

            // If the node isn't already being managed, we need to create a new one.
            if (null == node)
            {
                node = mNodeFactory.GetNode();
                node.pData = tile;

                created = true;

                // New nodes need to be registers with the Graph.
                AddNode(node);
            }

            return created;
        }
 /// <summary>
 /// Check if this GraphNode can be passed; eg. is it solid of empty?
 /// </summary>
 /// <param name="startingNode">The node we are travelling from.</param>
 /// <returns>True if if the node can be travelled to.</returns>
 public override Boolean IsPassable(GraphNode startingNode)
 {
     // This Node would never have been created if it weren't passable.
     return true;
 }
示例#23
0
        /// <summary>
        /// Removes a GraphNode from the Graph and also removes all the associated links to and from other
        /// GraphNode objects in this Graph.
        /// </summary>
        /// <param name="node">The GraphNode to remove.</param>
        public void RemoveTempNode(GraphNode node)
        {
            Cluster cluster = GetClusterAtPosition(node.pPosition);

            if (null != cluster)
            {

                for (Int32 i = 0; i < cluster.pNodes.Count; i++)
                {
                    if (node != cluster.pNodes[i])
                    {
                        UnlinkGraphNodes(node, cluster.pNodes[i]);
                    }
                }

                cluster.RemoveNode(node);
            }

            //DebugCheckForReferences(node);
            mNodeFactory.RecycleNode(node);
            RemoveNode(node);

            //DebugCheckNodes();
        }
示例#24
0
        /// <summary>
        /// Update the location that the Planner is attempting to reach. The position will be used
        /// to look up the tile at that position in the world.
        /// </summary>
        /// <param name="destination"></param>
        public Boolean SetDestination(GraphNode destination)
        {
            if (mEnd != destination)
            {
                mEnd = destination;
                mPathInvalidated = true;
                mSolved = false;

                return true;
            }

            return false;
        }
示例#25
0
        /// <summary>
        /// Checks if a node is reference by any Node in the Graph and their neighbours.
        /// </summary>
        /// <param name="node">The node to search for.</param>
        public void DebugCheckForReferences(GraphNode node)
        {
            for (Int32 i = 0; i < pNodes.Count; i++)
            {
                GraphNode next = pNodes[i];

                for (Int32 j = 0; j < next.pNeighbours.Count; j++)
                {
                    GraphNode nextNeighbour = next.pNeighbours[j].mGraphNode;

                    System.Diagnostics.Debug.Assert(nextNeighbour != node, "Found node!");
                }
            }
        }
示例#26
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="node">The GraphNode this PathNode will wrap.</param>
 public PathNode(GraphNode node)
 {
     mGraphNode = node;
 }