/// <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); }
/// <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); }