Beispiel #1
0
        /// <summary>
        /// Recursive function to check agents which this agent is waiting on.
        ///
        /// There are a few situations where the agent should abort waiting.
        ///
        /// 1. When this agent is waiting on an agent which is ultimately waiting for this agent.
        /// 2. When this agent is waiting for an agent which is involved in a circular conflict either itself, or some subsequent agent.
        /// 3. When this agent is waiting for a waiting agent which is ultimately waiting for a stationary agent.
        /// 4. When this agent is waiting for an agent who might be waiting, but its conflict handling setting is lower and therefor will never move again.
        ///
        /// Some of these options can be solved just by letting others solve their conflicts first.
        /// </summary>
        /// <param name="inNextNode">The next node this agent might traverse to.</param>
        /// <param name="inObstructingAgent">The obstructing agent encountered.</param>
        /// <param name="inCheckedAgents">All Checked agents including the obstructed agent.</param>
        private EConflictStatus CheckWaitingOccuypingAgents(PathNode inNextNode, NavTileAgent inObstructingAgent, List <NavTileAgent> inCheckedAgents, ref EAbortReason refAbortReason)
        {
            // Get all agents occupying the tile which the obstructing agent is waiting for, sorted per MovementStatus.
            Dictionary <EMovementStatus, List <NavTileAgent> > sortedAgents = inObstructingAgent.WaitingForTile.GetSortedOccupyingAgents(inObstructingAgent);

            List <NavTileAgent> agents;

            // Check if there are any stationary agents. If so, abort this path.
            if (sortedAgents.TryGetValue(EMovementStatus.Stationary, out agents))
            {
                refAbortReason = EAbortReason.EncounteredStationaryAgent;
                return(EConflictStatus.Abort);
            }
            else if (sortedAgents.TryGetValue(EMovementStatus.Waiting, out agents)) // Check if there are any waiting agents.
            {
                foreach (NavTileAgent agent in agents)
                {
                    // Is the agent found this agent or has it already been checked? Abort path
                    if (agent == this || inCheckedAgents.Contains(agent))
                    {
                        refAbortReason = EAbortReason.EncounteredCircularConflict;
                        return(EConflictStatus.Abort);
                    }

                    // Add the agent to the list
                    inCheckedAgents.Add(agent);

                    // Do this again.
                    return(CheckWaitingOccuypingAgents(inNextNode, agent, inCheckedAgents, ref refAbortReason));
                }
            }
            else // No entries of waiting or stationary agents.
            {
                // Set the timer to be used later and specify which tile this agent is waiting for.
                _didEncounterObstruction = true;
                _obstructionTimer        = _waitAfterFreeTile;

                _waitingForTile = NavTileManager.Instance.SurfaceManager.Data.GetTileData(inNextNode.TilePosition);
            }

            return(EConflictStatus.Processing);
        }
Beispiel #2
0
 private void OnPathAbortSetAnimationParameters(EAbortReason inAbortReason, Vector2Int inAbortPosition)
 {
     ResetAnimationParameters();
 }
Beispiel #3
0
        /// <summary>
        /// Function to check whether there is a conflict for this agent with the given parameters.
        /// </summary>
        /// <param name="inCurrentNode">The current node the agent is on.</param>
        /// <param name="inNextNode">The next node the agent might travel to.</param>
        /// <returns>A conflict status detailing how the conflict is handled.</returns>
        private EConflictStatus HandleConflict(PathNode inCurrentNode, PathNode inNextNode, out EAbortReason outAbortReason)
        {
            outAbortReason = EAbortReason.None;

            // Check if the next tile is free.
            TileData nextNodeTileData = NavTileManager.Instance.SurfaceManager.Data.GetTileData(inNextNode.TilePosition);

            NavTileAgent obstructingAgent;

            // Check if the next tile is obstructed.
            if (nextNodeTileData.IsObstructed(this, out obstructingAgent) || (_diagonalAllowed && IsMovingDiagonally(inCurrentNode.TilePosition, inNextNode.TilePosition) && IsPerpendicularObstructed(inCurrentNode.TilePosition, inNextNode.TilePosition, out obstructingAgent)))
            {
                // If so, set the position to be on the center of the tile.
                // The result of this function will stop moving the agent for at least one frame, so we correct it here instead.
                transform.position = inCurrentNode.WorldPosition;

                // If the conflict options is WaitOnWaitingAgent or higher, and the obstructing agent is waiting,
                // check if that agent isn't waiting indefinitely on this agent, itself or if there is some other circular conflict.
                if (_conflictOption >= EConflictOptions.WaitOnWaitingAgent && obstructingAgent.MovementStatus == EMovementStatus.Waiting)
                {
                    return(CheckWaitingOccuypingAgents(inNextNode, obstructingAgent, new List <NavTileAgent>()
                    {
                        obstructingAgent
                    }, ref outAbortReason));
                }

                // If the conflict option is WaitingOnTraversingAgent and the obstructing agent is traversing,
                // set the timer to be used later and specify which tile this agent is waiting for.
                if (_conflictOption >= EConflictOptions.WaitOnTraversingAgent && obstructingAgent.MovementStatus == EMovementStatus.Traversing)
                {
                    _didEncounterObstruction = true;
                    _obstructionTimer        = _waitAfterFreeTile;

                    _waitingForTile = NavTileManager.Instance.SurfaceManager.Data.GetTileData(inNextNode.TilePosition);

                    return(EConflictStatus.Processing);
                }

                // If this agent should abort on any obstruction, or there has been no result from the previous if's, abort the path.
                if (_conflictOption >= EConflictOptions.AbortOnObstruction || obstructingAgent.MovementStatus != EMovementStatus.Traversing)
                {
                    outAbortReason = EAbortReason.EncounteredObstruction;
                    return(EConflictStatus.Abort);
                }
            }
            else // No obstruction was found.
            {
                // Check if there was an obstruction since the last movement.
                if (_didEncounterObstruction && _conflictOption >= EConflictOptions.WaitOnTraversingAgent)
                {
                    // If so, start a timer.
                    _obstructionTimer -= Time.deltaTime;

                    if (_obstructionTimer > 0)
                    {
                        return(EConflictStatus.Processing);
                    }
                }

                // Update the tiles this agent should be occupying.
                UpdateTileOccupancy(inCurrentNode.TilePosition, inNextNode.TilePosition);
            }

            // No conflicts were found and everything is handled. Return a Success.
            return(EConflictStatus.Success);
        }