예제 #1
0
        /// <summary>
        /// Gets all the moves available for an entity on the map.
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="map"></param>
        /// <returns></returns>
        public static List<Move> GetMoves(Entity entity, TileMap map)
        {
            List<Move> moves = new List<Move>();

            if (entity == null || map == null)
            {
                return moves;
            }

            // Get the origin of the entity on the map
            var origin = map.ObjectsInMap.Find(m => m.Entity == entity).Location;

            foreach (var relativeDestination in entity.MoveBehavior.GetPossibleMovements())
            {
                // All possible movements are in relative to the origin, so add the origin
                // to make the destination be within the map
                var destination = relativeDestination + origin;

                if (entity.MoveBehavior.Capabilities.HasFlag(MoveBehavior.MoveCapabilities.Dig) ||
                 entity.MoveBehavior.Capabilities.HasFlag(MoveBehavior.MoveCapabilities.Jump) ||
                 entity.MoveBehavior.Capabilities.HasFlag(MoveBehavior.MoveCapabilities.Fly))
                {

                    Vector2 distanceVector = destination - origin;

                    if (((uint)Math.Floor(distanceVector.Length())) <= entity.MoveDistance)
                    {
                        List<Vector2> path = new List<Vector2>();
                        path.Add(origin);
                        path.Add(destination);

                        Move m = new Move(path);

                        moves.Add(m);
                    }
                }
                else
                {
                    Move m = FindMove(entity, map, origin, destination);
                    if (m != null)
                    {
                        moves.Add(m);
                    }
                }

            }

            return moves;
        }
예제 #2
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);
        }