コード例 #1
0
 /// <summary>
 /// Resets the agent's current drive path
 /// </summary>
 private void ResetPath()
 {
     m_connectionPath            = null;
     m_currentTargetACOConn      = null;
     m_currentTargetACOConnIndex = 0;
     m_currentACOConnRouteIndex  = 0;
 }
コード例 #2
0
    /// Generates ACOConnection list from the given goals and calculates an A* route between each
    private List <ACOConnection> CalculateGoalsAndRoutes(List <GameObject> goals)
    {
        List <ACOConnection> goalACOConnections = new List <ACOConnection>();

        foreach (GameObject goal in goals)
        {
            foreach (GameObject j in goals)
            {
                // If j isn't equal to current goal, add as a connection
                if (goal != j)
                {
                    /// Set ACO From and To
                    ACOConnection acoConnection = new ACOConnection();
                    acoConnection.SetConnection(goal, j, 1.0f);

                    /// Query A* navigate to see if route is possible
                    List <Connection> aStarRoute = this.NavigateAStar(acoConnection.FromNode, acoConnection.ToNode);
                    if (aStarRoute != null && aStarRoute.Count > 0)
                    {
                        /// Is a A* route, set and add
                        acoConnection.SetAStarRoute(aStarRoute);
                        goalACOConnections.Add(acoConnection);
                    }
                    else
                    {
                        Debug.LogError($"Unable to generate an A* path between '{goal.name}' and '{j.name}'");
                    }
                }
            }
        }
        return(goalACOConnections);
    }
コード例 #3
0
    // Log Route
    private void LogRoute(GameObject StartNode, int MaxPath, GameObject[] WaypointNodes, List <ACOConnection> Connections)
    {
        GameObject CurrentNode = null;

        foreach (GameObject GameObjectNode in WaypointNodes)
        {
            if (GameObjectNode.Equals(StartNode))
            {
                CurrentNode = GameObjectNode;
            }
        }

        ACOConnection HighestPheromoneConnection = null;
        string        Output    = "Route (Q: " + Q + ", Alpha: " + Alpha + ", Beta: " + Beta + ", EvaporationFactor: " + EvaporationFactor + ", DefaultPheromone: " + DefaultPheromone + "):\n";
        int           PathCount = 1;

        while (CurrentNode != null)
        {
            List <ACOConnection> AllFromConnections = AllConnectionsFromNode(CurrentNode, Connections);
            if (AllFromConnections.Count > 0)
            {
                HighestPheromoneConnection = AllFromConnections[0];
                foreach (ACOConnection aConnection in AllFromConnections)
                {
                    if (aConnection.PheromoneLevel > HighestPheromoneConnection.PheromoneLevel)
                    {
                        HighestPheromoneConnection = aConnection;
                    }
                }
                CurrentNode = HighestPheromoneConnection.ToNode;
                Output     += "| FROM: " + HighestPheromoneConnection.FromNode.name + ", TO: " + HighestPheromoneConnection.ToNode.name + " (Pheromone Level: " + HighestPheromoneConnection.PheromoneLevel + ") | \n";
            }
            else
            {
                CurrentNode = null;
            }

            // If the current node is the start node at this point then we have looped
            // through the path and should stop.
            if (CurrentNode != null && CurrentNode.Equals(StartNode))
            {
                CurrentNode = null;
                Output     += "HOME (Total Nodes:" + WaypointNodes.Length + ", Nodes in Route: " + PathCount + ").\n";
            }
            // If the path count is greater than a max we should stop.
            if (PathCount > MaxPath)
            {
                CurrentNode = null;
                Output     += "MAX PATH (Total Nodes:" + WaypointNodes.Length + ", Nodes in Route: " + PathCount + ").\n";
            }
            PathCount++;
        }
        Debug.Log(Output);
    }
コード例 #4
0
 /// <summary>
 /// Resets the agent's current drive path
 /// </summary>
 private void ResetPath()
 {
     m_acoConnectionPath         = null;
     m_currentTargetACOConn      = null;
     m_currentTargetACOConnIndex = 0;
     m_currentACOConnRouteIndex  = 0;
     m_startToACOPath            = null;
     m_startToACONavInfo         = null;
     m_acoToStartPath            = null;
     m_acoToStartNavInfo         = null;
     m_totalDuration             = 0f;
 }
コード例 #5
0
    public List <ACOConnection> GenerateRoute(GameObject StartNode, int MaxPath, List <ACOConnection> Connections)
    {
        GameObject           CurrentNode = StartNode;
        List <ACOConnection> Route       = new List <ACOConnection>();
        ACOConnection        HighestPheromoneConnection = null;
        int PathCount = 1;

        while (CurrentNode != null)
        {
            List <ACOConnection> AllFromConnections = AllConnectionsFromNode(CurrentNode, Connections);
            if (AllFromConnections.Count > 0)
            {
                HighestPheromoneConnection = AllFromConnections[0];
                foreach (ACOConnection aConnection in AllFromConnections)
                {
                    if (aConnection.PheromoneLevel > HighestPheromoneConnection.PheromoneLevel)
                    {
                        HighestPheromoneConnection = aConnection;
                    }
                }
                Route.Add(HighestPheromoneConnection);
                CurrentNode = HighestPheromoneConnection.ToNode;
            }
            else
            {
                CurrentNode = null;
            }

            // If the current node is the start node at this point then we have looped through the path and should stop.
            if (CurrentNode != null && CurrentNode.Equals(StartNode))
            {
                CurrentNode = null;
            }

            // If the path count is greater than a max we should stop.
            if (PathCount > MaxPath)
            {
                CurrentNode = null;
            }

            PathCount++;
        }
        return(Route);
    }
コード例 #6
0
    /// <summary>
    /// Drives the  along a certain connection path
    /// </summary>
    /// <param name="startToACOAStarPath">A* path from the agent start to the ACO path</param>
    /// <param name="acoConnections">The ACO connections path that goal around all goals</param>
    /// <param name="acoToStartAStarPath">A* path from the final ACO node back to the agent's start path</param>
    public void SetMovePath(List <Connection> startToACOAStarPath, List <ACOConnection> acoConnections, List <Connection> acoToStartAStarPath)
    {
        if (acoConnections == null || acoConnections != null && acoConnections.Count <= 0)
        {
            Debug.LogError("Unable to drive along connection path. acoConnections invalid");
            return;
        }

        /// Set navigation paths for this agent. Contains three paths:
        /// Agent start to the initial ACO start node
        /// The Total ACO path
        /// Final ACO node to the initial Agent start node
        m_acoConnectionPath = acoConnections;
        m_startToACOPath    = startToACOAStarPath;
        m_acoToStartPath    = acoToStartAStarPath;

        /// Set Move states to go from Start to the ACO start
        m_currentDrivePathTarget = NavigationTarget.StartToACO;

        /// Set movement vars to default values
        m_currentTargetACOConnIndex = 0;
        m_currentACOConnRouteIndex  = 0;
        m_currentTargetACOConn      = m_acoConnectionPath[m_currentTargetACOConnIndex];

        /// Set NavigateInfo for each A* path
        m_startToACONavInfo = new NavigateToInfo
        {
            TargetNode  = m_startToACOPath.FirstOrDefault().ToNode,
            TargetIndex = 0
        };
        m_acoToStartNavInfo = new NavigateToInfo
        {
            TargetNode  = m_acoToStartPath.FirstOrDefault().ToNode,
            TargetIndex = 0,
        };

        /// Set start position for agent
        this.transform.position = startToACOAStarPath.FirstOrDefault().FromNode.transform.position;

        Debug.Log($"Agent '{this.name}' path set! Start to ACO '{m_startToACOPath.Count}' Waypoints, ACO Total '{m_acoConnectionPath.Count}' waypoints, ACO to Start '{m_acoToStartPath.Count}' waypoints");
        m_ui.SetStatusText($"New Path: Moving to '{m_acoConnectionPath[m_acoConnectionPath.Count - 1].ToNode.name}'");
    }
コード例 #7
0
    /// <summary>
    /// Drives the  along a certain connection path
    /// </summary>
    /// <param name="connectionPath">List of connections to drive along</param>
    public void SetMovePath(GameObject start, List <ACOConnection> acoConnections)
    {
        if (acoConnections == null || acoConnections != null && acoConnections.Count <= 0)
        {
            Debug.LogError("Unable to drive along connection path. acoConnections invalid");
            return;
        }

        m_connectionPath = acoConnections;
        Debug.Log($"Squirrel '{this.name}' path set! '{m_connectionPath.Count}' connections");

        /// Set movement vars to default values
        m_currentTargetACOConnIndex = 0;
        m_currentACOConnRouteIndex  = 0;
        m_currentTargetACOConn      = m_connectionPath[m_currentTargetACOConnIndex];

        /// Set start position for agent
        this.transform.position = m_currentTargetACOConn.Route[m_currentACOConnRouteIndex].FromNode.transform.position;

        m_ui.SetStatusText($"New Path: Moving to '{m_connectionPath[m_connectionPath.Count - 1].ToNode.name}'");
    }
コード例 #8
0
 public void AddTravelledConnection(ACOConnection connection)
 {
     AntTravelledConnections.Add(connection);
 }
コード例 #9
0
    private void NavigateACO()
    {
        if (m_currentTargetACOConn != null)
        {
            /// Look at next target node
            GameObject targetNodeObj = m_currentTargetACOConn.Route[m_currentACOConnRouteIndex].ToNode;
            PerformLookAt(targetNodeObj.transform);

            if (!IsWaiting)
            {
                /// if not waiting, move toward next route node
                PerformMovementTo(targetNodeObj.transform.position);

                /// Check if agent reached next route node
                float nextNodeDistance = Vector3.Distance(transform.position, targetNodeObj.transform.position);
                if (nextNodeDistance < DESTINATION_TOLERANCE)
                {
                    /// Reached next route node, increment to next route node or to new ACOConnection
                    m_currentACOConnRouteIndex++;

                    /// Check RouteIndex is within route bounds
                    if (m_currentACOConnRouteIndex >= m_currentTargetACOConn.Route.Count)
                    {
                        /// If index is more than route, we've reached end and can move to next ACOConnection
                        m_currentACOConnRouteIndex = 0;

                        m_currentTargetACOConnIndex++;
                        /// Check if reached end of ACOConnection path
                        if (m_currentTargetACOConnIndex >= m_acoConnectionPath.Count)
                        {
                            ACOConnection finalConnection = m_acoConnectionPath[m_acoConnectionPath.Count - 1];
                            OnReachedPathEnd?.Invoke(this, finalConnection.ToNode);

                            m_ui.SetStatusText($"Finished path to '{finalConnection.ToNode.name}'");

                            m_currentDrivePathTarget = NavigationTarget.ACOToStart;
                            Debug.Log($"Agent '{this.name}' finished ACO path. Navigating A* path to Start");

                            return;
                        }
                        else
                        {
                            /// Move to next node in Route
                            //Debug.Log($"Reached ACO goal {m_currentTargetACOConn.ToNode.name}");

                            OnReachedGoal?.Invoke(this, m_currentTargetACOConn.ToNode);

                            /// Continue moving through ACOConnection path if not at end
                            m_currentTargetACOConn = m_acoConnectionPath[m_currentTargetACOConnIndex];

                            OnTravelNewConnection?.Invoke(this, m_currentTargetACOConn);
                            return;
                        }
                    }
                    else
                    {
                        /// Still more Route nodes to travel to, invoke event to specify the connection
                        Connection nextRouteConnection = m_currentTargetACOConn.Route[m_currentACOConnRouteIndex];
                        OnTravelNewConnection?.Invoke(this, nextRouteConnection);
                    }
                }
            }
        }
    }
コード例 #10
0
    void Update()
    {
        if (m_currentTargetACOConn != null)
        {
            GameObject targetNodeObj = m_currentTargetACOConn.Route[m_currentACOConnRouteIndex].ToNode;
            /// Look at next target node
            PerformLookAt(targetNodeObj.transform);

            if (!IsWaiting)
            {
                /// if not waiting, move toward next route node
                PerformMovementTo(targetNodeObj.transform.position);

                /// Check if agent reached next route node
                float nextNodeDistance = Vector3.Distance(transform.position, targetNodeObj.transform.position);
                if (nextNodeDistance < DESTINATION_TOLERANCE)
                {
                    /// Reached next route node, increment to next route node or to new ACOConnection
                    m_currentACOConnRouteIndex++;
                    if (m_currentACOConnRouteIndex >= m_currentTargetACOConn.Route.Count)
                    {
                        m_currentACOConnRouteIndex = 0;

                        m_currentTargetACOConnIndex++;
                        /// Check if reached end of ACOConnection path
                        if (m_currentTargetACOConnIndex >= m_connectionPath.Count)
                        {
                            ACOConnection finalConnection = m_connectionPath[m_connectionPath.Count - 1];
                            OnReachedPathEnd?.Invoke(this, finalConnection.ToNode);

                            m_ui.SetStatusText($"Finished path to '{finalConnection.ToNode.name}'");
                            ResetPath();

                            return;
                        }
                        else
                        {
                            /// Continue moving through ACOConnection path if not at end
                            m_currentTargetACOConn = m_connectionPath[m_currentTargetACOConnIndex];

                            OnTravelNewConnection?.Invoke(this, m_currentTargetACOConn);
                            return;
                        }
                    }
                }


                // Check if agent reached final ACOConnection node
                float finalNodeDistance = Vector3.Distance(transform.position, m_connectionPath[m_connectionPath.Count - 1].ToNode.transform.position);
                if (finalNodeDistance < DESTINATION_TOLERANCE && m_currentTargetACOConnIndex >= m_connectionPath.Count)
                {
                    // Invoke event for reached path end and remove target
                    ACOConnection finalConnection = m_connectionPath[m_connectionPath.Count - 1];
                    OnReachedPathEnd?.Invoke(this, finalConnection.ToNode);

                    m_ui.SetStatusText($"Finished path to '{finalConnection.ToNode.name}'");

                    ResetPath();
                }
            }
        }
    }
コード例 #11
0
    /*
     *  TotalNumAnts = Total number of ants in the simulation.
     *  Connections = Connections between nodes.
     *  WaypointNodes = All the waypoint nodes in the waypoint graph used by the ACO algorithm.
     */
    public List <ACOConnection> ACO(int IterationThreshold, int TotalNumAnts, GameObject[] WaypointNodes, List <ACOConnection> Connections, GameObject StartNode, int MaxPathLength)
    {
        if (StartNode == null)
        {
            Debug.Log("No Start node.");
            return(null);
        }

        // The node the ant is currently at.
        GameObject currentNode;
        // A list of all visited nodes.
        List <GameObject> VisitedNodes = new List <GameObject>();

        // Clear ants from previous runs.
        Ants.Clear();

        for (int i = 0; i < IterationThreshold; i++)
        {
            for (int i2 = 0; i2 < TotalNumAnts; i2++)
            {
                ACOAnt aAnt = new ACOAnt();

                // Randomly choose start node.
                currentNode    = WaypointNodes[Random.Range(0, WaypointNodes.Length)];
                aAnt.StartNode = currentNode;

                VisitedNodes.Clear();

                // Keep moving through the nodes until visited them all.
                // Keep looping until the number of nodes visited equals the number of nodes.
                while (VisitedNodes.Count < WaypointNodes.Length)
                {
                    // Get all connections from node.
                    List <ACOConnection> ConnectionsFromNodeAndNotVisited = AllConnectionsFromNodeAndNotVisited(currentNode, Connections, VisitedNodes);

                    // Sum the product of the pheromone level and the visibility
                    // factor on all allowed paths.
                    float TotalPheromoneAndVisibility = CalculateTotalPheromoneAndVisibility(ConnectionsFromNodeAndNotVisited);

                    // Calculate the product of the pheromone level and the visibility
                    // factor of the proposed path.
                    // Loop through the paths and check if visited destination already.
                    foreach (ACOConnection aConnection in ConnectionsFromNodeAndNotVisited)
                    {
                        // Not visited the path before.
                        float PathProbability = (Mathf.Pow(aConnection.PheromoneLevel, Alpha) * Mathf.Pow((1 / aConnection.Distance), Beta));
                        PathProbability = PathProbability / TotalPheromoneAndVisibility;

                        // Set path probability. Path probability is reset
                        // to zero at the end of each run.
                        aConnection.PathProbability = PathProbability;
                    }

                    // Travel down the path with the largest probability - or have a random
                    // choice if there are paths with equal probabilities.
                    // Loop through the paths and check if visited destination already.
                    ACOConnection largestProbability = null;
                    if (ConnectionsFromNodeAndNotVisited.Count > 0)
                    {
                        largestProbability = ConnectionsFromNodeAndNotVisited[0];
                        for (int i3 = 1; i3 < ConnectionsFromNodeAndNotVisited.Count; i3++)
                        {
                            if (ConnectionsFromNodeAndNotVisited[i3].PathProbability > largestProbability.PathProbability)
                            {
                                largestProbability = ConnectionsFromNodeAndNotVisited[i3];
                            }
                            else if (ConnectionsFromNodeAndNotVisited[i3].PathProbability == largestProbability.PathProbability)
                            {
                                // Currently, 100% of the time chooses shortest connection if probabilities are the same.
                                if (ConnectionsFromNodeAndNotVisited[i3].Distance < largestProbability.Distance)
                                {
                                    largestProbability = ConnectionsFromNodeAndNotVisited[i3];
                                }
                            }
                        }
                    }

                    // largestProbability contains the path to move down.
                    VisitedNodes.Add(currentNode);
                    if (largestProbability != null)
                    {
                        currentNode = largestProbability.ToNode;
                        aAnt.AddTravelledConnection(largestProbability);
                        aAnt.AddAntTourLength(largestProbability.Distance);
                    }
                } //~END: While loop.
                Ants.Add(aAnt);
            }

            // Update pheromone by formula Δτij.
            // Loop through the paths and check if visited destination already.
            foreach (ACOConnection aConnection in Connections)
            {
                float Sum = 0;
                foreach (ACOAnt TmpAnt in Ants)
                {
                    List <ACOConnection> TmpAntConnections = TmpAnt.AntTravelledConnections;
                    foreach (ACOConnection tmpConnection in TmpAntConnections)
                    {
                        if (aConnection.Equals(tmpConnection))
                        {
                            Sum += Q / TmpAnt.AntTourLength;
                        }
                    }
                }
                float NewPheromoneLevel = (1 - EvaporationFactor) * aConnection.PheromoneLevel + Sum;
                aConnection.PheromoneLevel = NewPheromoneLevel;
                // Reset path probability.
                aConnection.PathProbability = 0;
            }
        }

        MyRoute = GenerateRoute(StartNode, MaxPathLength, Connections);

        // Output connections and Pheromone to the log.
        //LogAnts();
        LogMyRoute(MyRoute);
        //LogRoute(StartNode, MaxPathLength, WaypointNodes, Connections);
        //LogConnections(Connections);


        return(MyRoute);
    }