Пример #1
0
        /// <summary>
        /// Checks whether the perpendicular tiles of a diagonal movement are obstructed.
        ///
        /// E.g. in the case of AB tiles, where an agent traverses over tiles A, positions B1 and B2 get checked for an obstructing agent.
        ///                     BA
        /// </summary>
        private bool IsPerpendicularObstructed(Vector2Int inCurrentTilePosition, Vector2Int inNextNodeTilePosition, out NavTileAgent outObstructingAgent)
        {
            outObstructingAgent = null;

            Vector2Int horizontalPosition = new Vector2Int(inCurrentTilePosition.x, inNextNodeTilePosition.y);
            Vector2Int verticalPosition   = new Vector2Int(inNextNodeTilePosition.x, inCurrentTilePosition.y);

            TileData horizontalTileData = NavTileManager.Instance.SurfaceManager.Data.GetTileData(horizontalPosition);
            TileData verticalTileData   = NavTileManager.Instance.SurfaceManager.Data.GetTileData(verticalPosition);

            NavTileAgent obstructingAgent;

            // Check whether there is an agent which is walking across the two relevant tiles.
            if (horizontalTileData.IsObstructed(this, out obstructingAgent) && obstructingAgent.GetPreviousPositionInPath() == verticalPosition ||
                verticalTileData.IsObstructed(this, out obstructingAgent) && obstructingAgent.GetPreviousPositionInPath() == horizontalPosition)
            {
                outObstructingAgent = obstructingAgent;

                return(true);
            }

            return(false);
        }
Пример #2
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);
        }