Example #1
0
        /// <summary>
        /// Processes the next node.
        /// </summary>
        /// <returns>The current pathing status</returns>
        protected override PathingStatus ProcessNext()
        {
            //First we need to explore the various exit conditions
            if (!_openSet.hasNext)
            {
                if (this.currentRequest.pathFinderOptions.navigateToNearestIfBlocked)
                {
                    UpdateGoal(_closestNode);
                    return(PathingStatus.Complete);
                }

                if (!this.goal.IsWalkableWithClearance(_unitProps))
                {
                    //Goal became unwalkable during a star, which can happen in both synchronous and async operation, since synchronous can have part of its processing split across frames if the time threshold is hit.
                    return(PathingStatus.DestinationBlocked);
                }

                //All routes have been explored without finding a route to destination, i.e. one does not (currently) exist
                return(PathingStatus.NoRouteExists);
            }

            //I doubt there is any reason to have this added complexity that the user needs to consider, just resize
            if (_openSet.count == _openSet.capacity)
            {
                UnityServices.debug.LogWarning("The pathing engine's heap capacity (" + _openSet.capacity + ") has been reached. If this happens often, it is recommended that you increase the initial heap size of the engine to avoid automatic resizing.\nDo this on the Path Service Component and increment it by 10 or so at a time to keep it as small as possible.");
                _openSet.Resize();
            }

            _current = _openSet.Remove();
            if (_current == this.goal)
            {
                //Hurray we found a route
                return(PathingStatus.Complete);
            }

            if (_closestNode.h > _current.h)
            {
                _closestNode = _current;
            }

            _current.isClosed = true;

            //Get potential successors
            _successorArray.Clear();
            GetWalkableSuccessors(_current, _successorArray);
            _current.GetVirtualNeighbours(_successorArray, _unitProps);

            //Assign costs
            var walkableCount = _successorArray.count;

            for (int i = 0; i < walkableCount; i++)
            {
                var n = _successorArray[i];
                if (n == null)
                {
                    break;
                }

                var cost = _current.g + this.cellCostStrategy.GetCellCost(n, _unitProps);

                var portal = _current as IPortalNode;
                if (portal != null)
                {
                    cost += portal.GetCost(portal.predecessor, n, this.costProvider);
                }
                else if (!(n is IPortalNode))
                {
                    cost += this.costProvider.GetMoveCost(_current, n);
                }

                //Instead of operating with an expanded set (closed set + open set) we simply evaluate the g value of the node, since g will only ever be > 0 if the node has been expanded.
                //This saves lots of memory over time and is even more O(1) than checking a hash set
                if (n.g > 0)
                {
                    //In the case that the neighbour has been evaluated in context to another node but gets a better cost in relation the current node, update its state.
                    if (n.g > cost)
                    {
                        n.g           = cost;
                        n.f           = cost + n.h;
                        n.predecessor = _current;

                        //If the node is closed, i.e. was removed from the open set, open it again. Otherwise update its position in the open set.
                        if (n.isClosed)
                        {
                            n.isClosed = false;
                            _openSet.Add(n);
                        }
                        else
                        {
                            _openSet.ReheapifyUpFrom(n);
                        }
                    }
                }
                else
                {
                    //Add the node to the open set
                    n.g           = cost;
                    n.h           = GetHeuristic(n, _current);
                    n.f           = cost + n.h;
                    n.predecessor = _current;
                    n.isClosed    = false;

                    _openSet.Add(n);
                    _expandedSet.Add(n);
                }
            }

            return(PathingStatus.Running);
        }