コード例 #1
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="origin">Point to start the path search</param>
        /// <param name="destination">Point to end the path search</param>
        /// <returns></returns>
        private static Move FindMove(Entity entity, TileMap map, Vector2 origin, Vector2 destination)
        {
            List<Vector2> path = new List<Vector2>();

            // There's always a path if the origin is the destination
            if (origin == destination)
            {
                path.Add(origin);
                return new Move(path);
            }

            // Use A* to try and make a path to the destination. Return null
            // if no path is found, or a list of moves (in order) if found.
            // Make sure to cache the destination for future use.
            // If the unit can fly, dig, or jump, just make sure the destination is within reach
            // and currently doesn't contain anything

            // For other cases, try and use A* to find a path
            Dictionary<Vector2, AStarValues> openPoints = new Dictionary<Vector2, AStarValues>();
            List<KeyValuePair<Vector2, AStarValues>> closedPoints = new List<KeyValuePair<Vector2, AStarValues>>();

            AStarValues originValues = new AStarValues();
            originValues.G = 0;
            originValues.Parent = origin;

            openPoints.Add(origin, originValues);
            KeyValuePair<Vector2, AStarValues> current = new KeyValuePair<Vector2, AStarValues>(origin, originValues);

            var relativePositions = GetRelativePositions();

            while (openPoints.Count > 0)
            {
                current = openPoints.OrderBy(p => p.Value.F).First<KeyValuePair<Vector2, AStarValues>>();

                // Drop the nextPoint from openPoints and add it to the closedPoints
                openPoints.Remove(current.Key);
                closedPoints.Add(current);

                if (current.Key == destination)
                {
                    break;
                }

                // Add to our open list the new set of squares to use.
                foreach (Vector2 position in relativePositions)
                {
                    Vector2 next = current.Key + position;

                    if (closedPoints.Any(p => p.Key == next) || !map.HasTile(next) || map.ObjectsInMap.Any<RenderObject>(p => p.Location == next))
                    {
                        continue;
                    }

                    AStarValues values = new AStarValues();
                    values.Parent = current.Key;

                    // Use the current G value plus the G value to move to the next point to find the actual G value
                    values.G = (int)GetMoveCost(position) + current.Value.G;

                    if (values.G > entity.MoveDistance)
                    {
                        // The distance is too great. don't add to the open points
                        continue;
                    }

                    if (next == destination)
                    {
                        openPoints[next] = values;
                        break;
                    }

                    // H is calculated using the Manhatten method. Essentially, calculate the move cost from the proposed square
                    // to the destination square using only horizontal and vertical movements.
                    values.H = (int)GetMoveCost(destination - next);

                    values.F = values.G + values.H;

                    if (openPoints.ContainsKey(next))
                    {
                        // Check the G score of the current path to this square. If this path is faster, then update the
                        // value to include the current values for going this direction
                        if (openPoints[next].G > values.G)
                        {
                            openPoints[next] = values;
                        }
                    }
                    else
                    {
                        openPoints[next] = values;
                    }
                }
            }

            // The origin always gets put into the closedList, so check for anything greater than 1
            var lastPoint = closedPoints.Last();

            if (lastPoint.Key != destination)
            {
                // Didn't find a path to the destination
                return null;
            }

            var currentPoint = lastPoint;
            while (currentPoint.Key != origin)
            {
                path.Add(currentPoint.Key);
                currentPoint = closedPoints.First(v => v.Key == currentPoint.Value.Parent);
            }

            //  Cache this path
            return new Move(path);
        }