예제 #1
0
        /// <summary>
        /// Calculates a path for the actor from multiple possible sources to target.
        /// Returned path is *reversed* and given target to source.
        /// The shortest path between a source and the target is returned.
        /// </summary>
        /// <remarks>
        /// Searches that provide a multiple source cells are slower than those than provide only a single source cell,
        /// as optimizations are possible for the single source case. Use searches from multiple source cells
        /// sparingly.
        /// </remarks>
        public List <CPos> FindUnitPathToTargetCell(
            Actor self, IEnumerable <CPos> sources, CPos target, BlockedByActor check,
            Func <CPos, int> customCost = null,
            Actor ignoreActor           = null,
            bool laneBias = true)
        {
            var sourcesList = sources.ToList();

            if (sourcesList.Count == 0)
            {
                return(NoPath);
            }

            var locomotor = GetLocomotor(self);

            // If the target cell is inaccessible, bail early.
            var inaccessible =
                !locomotor.CanMoveFreelyInto(self, target, check, ignoreActor) ||
                (!(customCost is null) && customCost(target) == PathGraph.PathCostForInvalidPath);

            if (inaccessible)
            {
                return(NoPath);
            }

            // When searching from only one source cell, some optimizations are possible.
            if (sourcesList.Count == 1)
            {
                var source = sourcesList[0];

                // For adjacent cells on the same layer, we can return the path without invoking a full search.
                if (source.Layer == target.Layer && (source - target).LengthSquared < 3)
                {
                    return new List <CPos>(2)
                           {
                               target, source
                           }
                }
                ;

                // With one starting point, we can use a bidirectional search.
                using (var fromTarget = PathSearch.ToTargetCell(
                           world, locomotor, self, new[] { target }, source, check, ignoreActor: ignoreActor))
                    using (var fromSource = PathSearch.ToTargetCell(
                               world, locomotor, self, new[] { source }, target, check, ignoreActor: ignoreActor, inReverse: true))
                        return(PathSearch.FindBidiPath(fromTarget, fromSource));
            }

            // With multiple starting points, we can only use a unidirectional search.
            using (var search = PathSearch.ToTargetCell(
                       world, locomotor, self, sourcesList, target, check, customCost, ignoreActor, laneBias))
                return(search.FindPath());
        }