Пример #1
0
 /// <summary>
 /// Returns an optimal route from startPosition to endPosition with options.
 /// </summary>
 /// <returns>The route.</returns>
 /// <param name="terrainCapability">Type of terrain that the unit can pass through</param>
 /// <param name="minAltitude">Minimum altitude (0..1)</param>
 /// <param name="maxAltitude">Maximum altutude (0..1)</param>
 /// <param name="maxSearchCost">Maximum search cost for the path finding algorithm. A value of -1 will use the global default defined by pathFindingMaxCost</param>
 public List <Vector2> FindRoute(City startCity, City endCity, TERRAIN_CAPABILITY terrainCapability = TERRAIN_CAPABILITY.Any, float minAltitude = 0, float maxAltitude = 1f, int maxSearchCost = -1, int maxSearchSteps = -1)
 {
     if (startCity == null || endCity == null)
     {
         return(null);
     }
     return(FindRoute(startCity.unity2DLocation, endCity.unity2DLocation, terrainCapability, minAltitude, maxAltitude, maxSearchCost, maxSearchSteps));
 }
Пример #2
0
        /// <summary>
        /// Get a list of cells which are nearer than a given distance in cell count with optional parameters
        /// </summary>
        public List <int> GetCellNeighbours(int cellIndex, int distance, float maxSearchCost = 0, TERRAIN_CAPABILITY terrainCapability = TERRAIN_CAPABILITY.Any)
        {
            if (cellIndex < 0 || cellIndex >= cells.Length)
            {
                return(null);
            }
            distance++;
            Cell       cell = cells[cellIndex];
            List <int> cc   = new List <int>();

            for (int x = cell.column - distance; x <= cell.column + distance; x++)
            {
                if (x < 0 || x >= _gridColumns)
                {
                    continue;
                }
                for (int y = cell.row - distance; y <= cell.row + distance; y++)
                {
                    if (y < 0 || y >= _gridRows)
                    {
                        continue;
                    }
                    if (x == cell.column && y == cell.row)
                    {
                        continue;
                    }
                    Cell otherCell = GetCell(y, x);
                    if (otherCell == null)
                    {
                        continue;
                    }
                    List <int> steps = FindRoute(cell, otherCell, terrainCapability, maxSearchCost);
                    if (steps != null && steps.Count <= distance)
                    {
                        cc.Add(GetCellIndex(otherCell));
                    }
                }
            }
            return(cc);
        }
Пример #3
0
        /// <summary>
        /// Returns an optimal route from starting Cell to destination Cell. The capability to move from one province to another is determined by the neighbours array of the Cell object.
        /// </summary>
        /// <returns>The result is a list of province indices.</returns>
        /// <param name="startingCell">The index for the starting province</param>
        /// <param name="destinationCell">The index for the destination province</param>
        /// <param name="terrainCapability">The allowed terrains for the route. Any/Ground/Water</param>
        /// <param name="maxSearchCost">Maximum search cost for the path finding algorithm. A value of -1 will use the global default defined by pathFindingMaxCost</param>
        /// <param name="minAltitude">Minimum terrain altitude allowed</param>
        /// <param name="minAltitude">Maximum terrain altitude allowed</param>
        public List <int> FindRoute(Cell startingCell, Cell destinationCell, out int totalCost, TERRAIN_CAPABILITY terrainCapability, int maxSearchCost = -1, float minAltitude = 0f, float maxAltitude = 1f, int maxSearchSteps = -1)
        {
            ComputeCellsCostsInfo();
            totalCost = 0;
            int startingCellIndex    = GetCellIndex(startingCell);
            int destinationCellIndex = GetCellIndex(destinationCell);

            if (destinationCellIndex == startingCellIndex || destinationCellIndex < 0 || startingCellIndex < 0)
            {
                return(null);
            }
            List <int> routePoints = null;

            if (finderCells == null)
            {
                return(null);
            }
            finderCells.Formula           = _pathFindingHeuristicFormula;
            finderCells.MaxSearchCost     = maxSearchCost < 0 ? _pathFindingMaxCost : maxSearchCost;
            finderCells.MaxSteps          = maxSearchSteps < 0 ? _pathFindingMaxSteps : maxSearchSteps;
            finderCells.TerrainCapability = terrainCapability;
            finderCells.MinAltitude       = minAltitude;
            finderCells.MaxAltitude       = maxAltitude;

            if (OnPathFindingCrossCell != null)
            {
                finderCells.OnCellCross = FindRouteCellValidator;
            }
            else
            {
                finderCells.OnCellCross = null;
            }
            Point startPoint            = new Point(startingCell.column, startingCell.row);
            Point endPoint              = new Point(destinationCell.column, destinationCell.row);
            List <PathFinderNode> route = finderCells.FindPath(startPoint, endPoint, out totalCost);

            if (route != null)
            {
                int routeCount = route.Count;
                routePoints = new List <int> (routeCount);
                for (int r = routeCount - 1; r >= 0; r--)
                {
                    routePoints.Add(route [r].Y * _gridColumns + route [r].X);
                }
            }
            else
            {
                return(null);                   // no route available
            }

            // Add final step if it's appropiate
            return(routePoints);
        }
Пример #4
0
        /// <summary>
        /// Returns an optimal route from starting Cell to destination Cell. The capability to move from one province to another is determined by the neighbours array of the Cell object.
        /// </summary>
        /// <returns>The result is a list of province indices.</returns>
        /// <param name="startingCell">The index for the starting province</param>
        /// <param name="destinationCell">The index for the destination province</param>
        /// <param name="terrainCapability">The allowed terrains for the route. Any/Ground/Water</param>
        /// <param name="maxSearchCost">Maximum search cost for the path finding algorithm. A value of -1 will use the global default defined by pathFindingMaxCost</param>
        /// <param name="maxSearchSteps">Maximum number of steps for the path finding algorithm. A value of -1 will use the global default defined by pathFindingMaxSteps</param>
        public List <int> FindRoute(Cell startingCell, Cell destinationCell, TERRAIN_CAPABILITY terrainCapability = TERRAIN_CAPABILITY.Any, int maxSearchCost = -1, int maxSearchSteps = -1)
        {
            int dummy;

            return(FindRoute(startingCell, destinationCell, out dummy, terrainCapability, maxSearchCost, maxSearchSteps));
        }
Пример #5
0
        /// <summary>
        /// Returns an optimal route from startPosition to endPosition with options.
        /// </summary>
        /// <returns>The route.</returns>
        /// <param name="startPosition">Start position in map coordinates (-0.5...0.5)</param>
        /// <param name="endPosition">End position in map coordinates (-0.5...0.5)</param>
        /// <param name="totalCost">The total cost of traversing the path</param>
        /// <param name="terrainCapability">Type of terrain that the unit can pass through</param>
        /// <param name="minAltitude">Minimum altitude (0..1)</param>
        /// <param name="maxAltitude">Maximum altutude (0..1)</param>
        /// <param name="maxSearchCost">Maximum search cost for the path finding algorithm. A value of -1 will use the global default defined by pathFindingMaxCost</param>
        public List <Vector2> FindRoute(Vector2 startPosition, Vector2 endPosition, out int totalCost, TERRAIN_CAPABILITY terrainCapability = TERRAIN_CAPABILITY.Any, float minAltitude = 0, float maxAltitude = 1f, int maxSearchCost = -1, int maxSearchSteps = -1)
        {
            ComputeRouteMatrix(terrainCapability, minAltitude, maxAltitude);
            totalCost = 0;
            Point startingPoint = new Point((int)((startPosition.x + 0.5f) * EARTH_ROUTE_SPACE_WIDTH),
                                            (int)((startPosition.y + 0.5f) * EARTH_ROUTE_SPACE_HEIGHT));
            Point endingPoint = new Point((int)((endPosition.x + 0.5f + 0.5f / EARTH_ROUTE_SPACE_WIDTH) * EARTH_ROUTE_SPACE_WIDTH),
                                          (int)((endPosition.y + 0.5f + 0.5f / EARTH_ROUTE_SPACE_HEIGHT) * EARTH_ROUTE_SPACE_HEIGHT));

            endingPoint.X = Mathf.Clamp(endingPoint.X, 0, EARTH_ROUTE_SPACE_WIDTH - 1);
            endingPoint.Y = Mathf.Clamp(endingPoint.Y, 0, EARTH_ROUTE_SPACE_HEIGHT - 1);

            // Helper to find a minimum path in case the destination position is on a different terrain type
            if (terrainCapability == TERRAIN_CAPABILITY.OnlyWater)
            {
                int arrayIndex = endingPoint.Y * EARTH_ROUTE_SPACE_WIDTH + endingPoint.X;
                if ((earthRouteMatrix [arrayIndex] & 4) == 0)
                {
                    int regionIndex  = -1;
                    int countryIndex = GetCountryIndex(endPosition, out regionIndex);
                    if (countryIndex >= 0 && regionIndex >= 0)
                    {
                        List <Vector2> coastPositions      = GetCountryCoastalPoints(countryIndex, regionIndex, 0.001f);
                        float          minDist             = float.MaxValue;
                        Vector2        bestPosition        = Misc.Vector2zero;
                        int            coastPositionsCount = coastPositions.Count;
                        // Get nearest position to the ship which is on water
                        for (int k = 0; k < coastPositionsCount; k++)
                        {
                            Vector2 waterPosition;
                            if (ContainsWater(coastPositions [k], 0.001f, out waterPosition))
                            {
                                float dist = FastVector.SqrDistance(ref endPosition, ref waterPosition);                                  // (endPosition - waterPosition).sqrMagnitude;
                                if (dist < minDist)
                                {
                                    minDist      = dist;
                                    bestPosition = waterPosition;
                                }
                            }
                        }
                        if (minDist < float.MaxValue)
                        {
                            endPosition = bestPosition;
                        }
                        endingPoint = new Point((int)((endPosition.x + 0.5f + 0.5f / EARTH_ROUTE_SPACE_WIDTH) * EARTH_ROUTE_SPACE_WIDTH),
                                                (int)((endPosition.y + 0.5f + 0.5f / EARTH_ROUTE_SPACE_HEIGHT) * EARTH_ROUTE_SPACE_HEIGHT));
                        arrayIndex = endingPoint.Y * EARTH_ROUTE_SPACE_WIDTH + endingPoint.X;
                        if ((earthRouteMatrix [arrayIndex] & 4) == 0)
                        {
                            Vector2 direction = Misc.Vector2zero;
                            for (int k = 1; k <= 10; k++)
                            {
                                if (k == 10 || startPosition == endPosition)
                                {
                                    return(null);
                                }
                                FastVector.NormalizedDirection(ref endPosition, ref startPosition, ref direction);
                                Vector2 p = endPosition + direction * (float)k / EARTH_ROUTE_SPACE_WIDTH;
                                endingPoint = new Point((int)((p.x + 0.5f + 0.5f / EARTH_ROUTE_SPACE_WIDTH) * EARTH_ROUTE_SPACE_WIDTH),
                                                        (int)((p.y + 0.5f + 0.5f / EARTH_ROUTE_SPACE_HEIGHT) * EARTH_ROUTE_SPACE_HEIGHT));
                                arrayIndex = endingPoint.Y * EARTH_ROUTE_SPACE_WIDTH + endingPoint.X;
                                if ((earthRouteMatrix [arrayIndex] & 4) > 0)
                                {
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            List <Vector2> routePoints = null;

            // Minimum distance for routing?
            if (Mathf.Abs(endingPoint.X - startingPoint.X) > 0 || Mathf.Abs(endingPoint.Y - startingPoint.Y) > 0)
            {
                finder.Formula       = _pathFindingHeuristicFormula;
                finder.MaxSearchCost = maxSearchCost < 0 ? _pathFindingMaxCost : maxSearchCost;
                finder.MaxSteps      = maxSearchSteps < 0 ? _pathFindingMaxSteps : maxSearchSteps;
                if (_pathFindingEnableCustomRouteMatrix)
                {
                    finder.OnCellCross = FindRoutePositionValidator;
                }
                else
                {
                    finder.OnCellCross = null;
                }
                List <PathFinderNode> route = finder.FindPath(startingPoint, endingPoint, out totalCost);
                if (route != null)
                {
                    routePoints = new List <Vector2> (route.Count);
                    routePoints.Add(startPosition);
                    for (int r = route.Count - 1; r >= 0; r--)
                    {
                        float   x       = (float)route [r].X / EARTH_ROUTE_SPACE_WIDTH - 0.5f;
                        float   y       = (float)route [r].Y / EARTH_ROUTE_SPACE_HEIGHT - 0.5f;
                        Vector2 stepPos = new Vector2(x, y);

                        // due to grid effect the first step may be farther than the current position, so we skip it in that case.
                        if (r == route.Count - 1 && (endPosition - startPosition).sqrMagnitude < (endPosition - stepPos).sqrMagnitude)
                        {
                            continue;
                        }

                        routePoints.Add(stepPos);
                    }
                }
                else
                {
                    return(null);                       // no route available
                }
            }

            // Add final step if it's appropiate
            bool hasWater = ContainsWater(endPosition);

            if (terrainCapability == TERRAIN_CAPABILITY.Any ||
                (terrainCapability == TERRAIN_CAPABILITY.OnlyWater && hasWater) ||
                (terrainCapability == TERRAIN_CAPABILITY.OnlyGround && !hasWater))
            {
                if (routePoints == null)
                {
                    routePoints = new List <Vector2> ();
                    routePoints.Add(startPosition);
                    routePoints.Add(endPosition);
                }
                else
                {
                    routePoints [routePoints.Count - 1] = endPosition;
                }
            }

            // Check that ground units ends in a position where GetCountryIndex returns a valid index
            if (terrainCapability == TERRAIN_CAPABILITY.OnlyGround)
            {
                int     rr = routePoints.Count - 1;
                Vector2 dd = routePoints [rr - 1] - routePoints [rr];
                dd *= 0.1f;
                while (GetCountryIndex(routePoints [rr]) < 0)
                {
                    routePoints [rr] += dd;
                }
            }

            return(routePoints);
        }
Пример #6
0
        /// <summary>
        /// Returns an optimal route from startPosition to endPosition with options.
        /// </summary>
        /// <returns>The route.</returns>
        /// <param name="startPosition">Start position in map coordinates (-0.5...0.5)</param>
        /// <param name="endPosition">End position in map coordinates (-0.5...0.5)</param>
        /// <param name="terrainCapability">Type of terrain that the unit can pass through</param>
        /// <param name="minAltitude">Minimum altitude (0..1)</param>
        /// <param name="maxAltitude">Maximum altutude (0..1)</param>
        /// <param name="maxSearchCost">Maximum search cost for the path finding algorithm. A value of -1 will use the global default defined by pathFindingMaxCost</param>
        public List <Vector2> FindRoute(Vector2 startPosition, Vector2 endPosition, TERRAIN_CAPABILITY terrainCapability = TERRAIN_CAPABILITY.Any, float minAltitude = 0, float maxAltitude = 1f, int maxSearchCost = -1, int maxSearchSteps = -1)
        {
            int dummy;

            return(FindRoute(startPosition, endPosition, out dummy, terrainCapability, minAltitude, maxAltitude, maxSearchCost, maxSearchSteps));
        }
Пример #7
0
        /// <summary>
        /// Returns an optimal route from startPosition to endPosition with options.
        /// </summary>
        /// <returns>The route.</returns>
        /// <param name="terrainCapability">Type of terrain that the unit can pass through</param>
        /// <param name="minAltitude">Minimum altitude (0..1)</param>
        /// <param name="maxAltitude">Maximum altutude (0..1)</param>
        /// <param name="maxSearchCost">Maximum search cost for the path finding algorithm. A value of -1 will use the global default defined by pathFindingMaxCost</param>
        public List <Vector2> FindRoute(string startCityName, string startCountryName, string endCityName, string endCountryName, TERRAIN_CAPABILITY terrainCapability = TERRAIN_CAPABILITY.Any, float minAltitude = 0, float maxAltitude = 1f, int maxSearchCost = -1, int maxSearchSteps = -1)
        {
            City city1 = GetCity(startCityName, startCountryName);
            City city2 = GetCity(endCityName, endCountryName);

            if (city1 == null || city2 == null)
            {
                return(null);
            }
            return(FindRoute(city1, city2, terrainCapability, minAltitude, maxAltitude, maxSearchCost, maxSearchSteps));
        }
Пример #8
0
        void ComputeRouteMatrix(TERRAIN_CAPABILITY terrainCapability, float minAltitude, float maxAltitude)
        {
            bool computeMatrix = false;
            byte thisMatrix    = 1;

            // prepare matrix
            if (earthRouteMatrix == null)
            {
                earthRouteMatrix   = new byte[EARTH_ROUTE_SPACE_WIDTH * EARTH_ROUTE_SPACE_HEIGHT];
                computedMatrixBits = 0;
            }

            // prepare water mask data
            bool checkWater = terrainCapability != TERRAIN_CAPABILITY.Any;

            if (checkWater)
            {
                computeMatrix = CheckRouteWaterMask();
            }

            // check elevation data if needed
            bool checkElevation = minAltitude > 0f || maxAltitude < 1.0f;

            if (checkElevation)
            {
                if (viewportElevationPoints == null)
                {
                    Debug.LogError("Viewport needs to be initialized before calling using Path Finding functions.");
                    return;
                }
                if (minAltitude != earthRouteMatrixWithElevationMinAltitude || maxAltitude != earthRouteMatrixWithElevationMaxAltitude)
                {
                    computeMatrix = true;
                    earthRouteMatrixWithElevationMinAltitude = minAltitude;
                    earthRouteMatrixWithElevationMaxAltitude = maxAltitude;
                }
            }
            else
            {
                if (terrainCapability == TERRAIN_CAPABILITY.OnlyGround)
                {
                    thisMatrix = 2;
                }
                else
                {
                    thisMatrix = 4; // water
                }
                if ((computedMatrixBits & thisMatrix) == 0)
                {
                    computeMatrix       = true;
                    computedMatrixBits |= thisMatrix;   // mark computedMatrixBits
                }
            }

            // Compute route
            if (computeMatrix)
            {
                int   jj_waterMask = 0, kk_waterMask;
                int   jj_terrainElevation = 0, kk_terrainElevation;
                bool  dry = false;
                float elev = 0;
                for (int j = 0; j < EARTH_ROUTE_SPACE_HEIGHT; j++)
                {
                    int jj = j * EARTH_ROUTE_SPACE_WIDTH;
                    if (checkWater)
                    {
                        jj_waterMask = (int)((j * (float)earthWaterMaskHeight / EARTH_ROUTE_SPACE_HEIGHT)) * earthWaterMaskWidth;
                    }
                    if (checkElevation)
                    {
                        jj_terrainElevation = ((int)(j * (float)heightmapTextureHeight / EARTH_ROUTE_SPACE_HEIGHT)) * heightmapTextureWidth;
                    }
                    for (int k = 0; k < EARTH_ROUTE_SPACE_WIDTH; k++)
                    {
                        bool setBit = false;
                        // Check altitude
                        if (checkElevation)
                        {
                            kk_terrainElevation = (int)(k * (float)heightmapTextureWidth / EARTH_ROUTE_SPACE_WIDTH);
                            elev = viewportElevationPoints[jj_terrainElevation + kk_terrainElevation];
                        }
                        if (elev >= minAltitude && elev <= maxAltitude)
                        {
                            if (checkWater)
                            {
                                kk_waterMask = (int)(k * (float)earthWaterMaskWidth / EARTH_ROUTE_SPACE_WIDTH);
                                dry          = !earthWaterMask.GetBit(jj_waterMask + kk_waterMask);
                            }
                            if (terrainCapability == TERRAIN_CAPABILITY.Any ||
                                terrainCapability == TERRAIN_CAPABILITY.OnlyGround && dry ||
                                terrainCapability == TERRAIN_CAPABILITY.OnlyWater && !dry)
                            {
                                setBit = true;
                            }
                        }
                        if (setBit)     // set navigation bit
                        {
                            earthRouteMatrix[jj + k] |= thisMatrix;
                        }
                        else            // clear navigation bit
                        {
                            earthRouteMatrix[jj + k] &= (byte)(byte.MaxValue ^ thisMatrix);
                        }
                    }
                }
            }

            if (finder == null)
            {
                if (_customRouteMatrix == null || !_pathFindingEnableCustomRouteMatrix)
                {
                    PathFindingCustomRouteMatrixReset();
                }
                finder = new PathFinderFast(earthRouteMatrix, thisMatrix, EARTH_ROUTE_SPACE_WIDTH, EARTH_ROUTE_SPACE_HEIGHT, _customRouteMatrix);
            }
            else
            {
                if (computeMatrix || thisMatrix != lastMatrix)
                {
                    lastMatrix = thisMatrix;
                    finder.SetCalcMatrix(earthRouteMatrix, thisMatrix);
                }
            }
        }