Пример #1
0
 void Start()
 {
     rb = GetComponent <Rigidbody2D>();
     initialPosition = new TimeWaypoint(transform.position, transform.rotation, startVelocity);
     lastVelocity    = startVelocity;
     _player         = GameObject.Find("Player").transform;
 }
Пример #2
0
        /// <summary>
        /// Estimates the time it takes to travel from one waypoint to another.
        /// </summary>
        /// <param name="from">The start node.</param>
        /// <param name="to">The destination node.</param>
        /// <returns>The estimated time it takes to travel between the nodes.</returns>
        private double EstimateTravelTime(TimeWaypoint from, Waypoint to)
        {
            // Init, if not done yet
            if (_timeGraph == null)
            {
                _timeGraph = new TimeGraph(_instance);
            }
            // --> Calculate time needed for driving the given distance
            double travelTime = Distances.CalculateEuclid(from.OriginalWaypoint, to, _instance.WrongTierPenaltyDistance) / _timeGraph.Speed;

            // Check whether we reached the goal already, thus, eliminating the need for turning
            if (from.OriginalWaypoint == to)
            {
                // No turning necessary - only consider time for driving
                return(travelTime);
            }
            else
            {
                // In addition to the drive time also consider the effort for turning
                return
                    // --> Calculate time needed for turning towards new orientation
                    (Math.Abs(Circle.GetOrientationDifference(from.Orientation,
                                                              Circle.GetOrientation(from.OriginalWaypoint.X, from.OriginalWaypoint.Y, to.X, to.Y))) / TimeGraph.PI2 * _timeGraph.TurnSpeed +
                     // --> Add time for driving
                     travelTime);
            }
        }
Пример #3
0
 /// <summary>
 /// Calculates the time to move from one time-waypoint to another.
 /// </summary>
 /// <param name="from">The start node.</param>
 /// <param name="to">The destination node.</param>
 /// <returns>The time for traveling from one node to the other.</returns>
 public double GetTimeNeededToTravel(TimeWaypoint from, TimeWaypoint to)
 {
     return
         // --> Calculate time needed for turning towards new orientation
         (Math.Abs(Circle.GetOrientationDifference(from.Orientation, to.Orientation)) / PI2 * TurnSpeed +
          // --> Calculate time needed for driving the given distance
          Distances.CalculateEuclid(from.OriginalWaypoint, to.OriginalWaypoint, Instance.WrongTierPenaltyDistance) / Speed);
 }
Пример #4
0
 /// <summary>
 /// Creates a new time-waypoint graph.
 /// </summary>
 /// <param name="instance">The instance that the graph shall reflect.</param>
 public TimeGraph(Instance instance)
 {
     // Save instance
     Instance = instance;
     // Determine robot characteristics (act as if robots have infinite acceleration)
     Speed     = instance.Bots.Min(b => b.MaxVelocity);
     TurnSpeed = instance.Bots.Min(b => b.TurnSpeed) * TURN_SPEED_SLOW_FACTOR;
     // Create base graph for storing time information
     foreach (var from in instance.Waypoints)
     {
         foreach (var to in from.Paths)
         {
             TimeWaypoint timeWP = new TimeWaypoint()
             {
                 // Emulated waypoint is the "to-part" of the connection
                 OriginalWaypoint = to,
                 // Store from waypoint just for completeness
                 InboundWaypoint = from,
                 // The orientation the bot is in when approaching the "to-part" of the connection is derived from the "from-part" of it
                 Orientation = Circle.GetOrientation(from.X, from.Y, to.X, to.Y),
             };
             TimeWaypointsOfConnections[from, to] = timeWP;
             if (!TimeWaypointsOfOriginalWaypoints.ContainsKey(to))
             {
                 TimeWaypointsOfOriginalWaypoints[to] = new HashSet <TimeWaypoint>();
             }
             TimeWaypointsOfOriginalWaypoints[to].Add(timeWP);
             TimeWaypoints.Add(timeWP);
         }
     }
     // Add time information for all connections to the graph
     foreach (var timeWPFrom in TimeWaypoints)
     {
         foreach (var connectedWP in timeWPFrom.OriginalWaypoint.Paths)
         {
             TimeWaypoint timeWPTo = TimeWaypointsOfConnections[timeWPFrom.OriginalWaypoint, connectedWP];
             timeWPFrom.Edges.Add(new Tuple <TimeWaypoint, double>(
                                      // --> Store node we approach when using the connection
                                      timeWPTo,
                                      // --> Calculate time needed to travel along the connection, i.e. the time for turning towards the connected waypoint + the time for driving to it
                                      GetTimeNeededToTravel(timeWPFrom, timeWPTo)));
         }
     }
     // Add turn on the spot information too
     foreach (var timeWPFrom in TimeWaypoints)
     {
         foreach (var timeWPTo in TimeWaypointsOfOriginalWaypoints[timeWPFrom.OriginalWaypoint].Where(to => to != timeWPFrom))
         {
             timeWPFrom.Edges.Add(new Tuple <TimeWaypoint, double>(
                                      // --> Store node of time graph
                                      timeWPTo,
                                      // --> Calculate time for turning on the spot
                                      GetTimeNeededToTravel(timeWPFrom, timeWPTo)));
         }
     }
 }
Пример #5
0
        /// <summary>
        /// Uses A* to find the distance from the startNode to the destinationNode.
        /// </summary>
        /// <param name="start">The starting waypoint.</param>
        /// <param name="destination">The destination waypoint.</param>
        /// <param name="wrongTierPenalty">The penalty for the waypoints not being on the same tier.</param>
        /// <param name="emulatePodCarrying">Indicates whether to calculate a path that is ensured to be safe for carrying a pod on it.</param>
        /// <returns>The distance.</returns>
        private double CalculateShortestPath(Waypoint start, Waypoint destination, double wrongTierPenalty, bool emulatePodCarrying)
        {
            if (start == null || destination == null)
            {
                return(double.PositiveInfinity);
            }
            if (start == destination)
            {
                return(0);
            }
            // Determine shortest time
            double shortestTime = double.PositiveInfinity;

            foreach (var startNode in _timeGraph.TimeWaypointsOfOriginalWaypoints[start])
            {
                Dictionary <TimeWaypoint, TimeWaypointSearchDatapoint> openLocations   = new Dictionary <TimeWaypoint, TimeWaypointSearchDatapoint>();
                Dictionary <TimeWaypoint, TimeWaypointSearchDatapoint> closedLocations = new Dictionary <TimeWaypoint, TimeWaypointSearchDatapoint>();
                openLocations[startNode] = new TimeWaypointSearchDatapoint(0.0, EstimateTravelTime(startNode, destination), startNode, null, 0);

                // Loop until end is found
                while (true)
                {
                    // Find lowest cost waypoint in openLocations
                    KeyValuePair <TimeWaypoint, TimeWaypointSearchDatapoint> currentNodeKVP = openLocations.ArgMin(w => w.Value.TimeTraveled + w.Value.TimeToGoal);
                    // Something wrong happened -can't find the end
                    if (currentNodeKVP.Equals(default(KeyValuePair <TimeWaypoint, TimeWaypointSearchDatapoint>)))
                    {
                        break;
                    }
                    TimeWaypoint currentNode = currentNodeKVP.Key;

                    // Grab the details about the current waypoint
                    TimeWaypointSearchDatapoint currentNodeData = currentNodeKVP.Value;

                    // If the closest is also the destination or out of iterations
                    if (currentNode.OriginalWaypoint == destination)
                    {
                        // Update traveled time
                        shortestTime = Math.Min(shortestTime, currentNodeData.TimeTraveled);
                        break;
                    }

                    // Transfer closest from open to closed list
                    closedLocations[currentNode] = currentNodeKVP.Value;
                    openLocations.Remove(currentNode);

                    // Expand all the moves
                    foreach (var edge in currentNode.Edges)
                    {
                        // Check whether the node is already on closed
                        if (closedLocations.ContainsKey(edge.Item1))
                        {
                            // Don't deal with anything already on the closed list (don't want loops)
                            continue;
                        }

                        // Can't use a pod storage location for the path
                        if (emulatePodCarrying && edge.Item1.OriginalWaypoint.PodStorageLocation && edge.Item1.OriginalWaypoint != destination)
                        {
                            continue;
                        }

                        // Tag on more distance for a node on the wrong level
                        double additionalDistance = 0;
                        if (edge.Item1.OriginalWaypoint.Tier != destination.Tier)
                        {
                            additionalDistance += wrongTierPenalty;
                        }

                        // If it's not in the open list, add it
                        if (!openLocations.ContainsKey(edge.Item1))
                        {
                            openLocations[edge.Item1] =
                                new TimeWaypointSearchDatapoint(
                                    currentNodeData.TimeTraveled + edge.Item2,                        // The distance already traveled
                                    EstimateTravelTime(edge.Item1, destination) + additionalDistance, // The approximate distance to the goal
                                    edge.Item1,                                                       // The node itself
                                    currentNodeData,                                                  // Parent data
                                    currentNodeData.Depth + 1);                                       // The current depth
                        }
                        else
                        {
                            // It's already in the open list, but see if this new path is better
                            TimeWaypointSearchDatapoint oldPath = openLocations[edge.Item1];
                            // Replace it with the new one, if better
                            if (oldPath.TimeTraveled > currentNodeData.TimeTraveled + edge.Item2)
                            {
                                oldPath.TimeTraveled = currentNodeData.TimeTraveled + edge.Item2;                        // The distance already traveled
                                oldPath.TimeToGoal   = EstimateTravelTime(edge.Item1, destination) + additionalDistance; // The approximate distance to the goal
                                oldPath.Waypoint     = edge.Item1;                                                       // The node itself
                                oldPath.ParentMove   = currentNodeData;                                                  // Parent data
                                oldPath.Depth        = currentNodeData.Depth + 1;                                        // The current depth
                            }
                        }
                    }
                }
            }
            // Return time
            return(shortestTime);
        }
Пример #6
0
 /// <summary>
 /// Creates a new waypoint search data object.
 /// </summary>
 /// <param name="timeTraveled">The time traveled so far.</param>
 /// <param name="timeToGoal">The estimated time towards the destination.</param>
 /// <param name="waypoint">The waypoint this data object belongs to.</param>
 /// <param name="parentMove">The data of the parent.</param>
 /// <param name="depth">The steps we did to come here.</param>
 public TimeWaypointSearchDatapoint(double timeTraveled, double timeToGoal, TimeWaypoint waypoint, TimeWaypointSearchDatapoint parentMove, int depth)
 {
     TimeTraveled = timeTraveled; TimeToGoal = timeToGoal; Waypoint = waypoint; ParentMove = parentMove; Depth = depth;
 }