// Informational methods. public IEnumerable <Vector2Int> GetVisionPath(Vector2Int origin, Vector2Int destination) { Vector2Int difference = destination - origin; Vector2Int stencilDifference = new Vector2Int(Mathf.Abs(difference.x), Mathf.Abs(difference.y)); if (!Enumerables.IsIndex(stencilDifference, visionPaths)) { return(null); } var visionPath = visionPaths[stencilDifference.x, stencilDifference.y]; if (visionPath == null) { return(null); } IEnumerable <Vector2Int> Iterate() { foreach (var localPosition in visionPath) { var position = localPosition; position.x *= (int)Mathf.Sign(difference.x); position.y *= (int)Mathf.Sign(difference.y); position += origin; yield return(position); } }; return(Iterate()); }
// Information methods. public List <Vector2Int> TryFindShortestPath(Vector2Int originPosition, Vector2Int destinationPosition) { if (!Enumerables.IsIndex(originPosition, nodes) || !Enumerables.IsIndex(destinationPosition, nodes)) { return(null); } var originNode = nodes[originPosition.x, originPosition.y]; var destinationNode = nodes[destinationPosition.x, destinationPosition.y]; if (originNode is null || destinationNode is null) { return(null); } var nodePath = AStarSparse.TryFindShortestPath( originNode.AsVision, destinationNode.AsVision, destinationNode.AsVision.CalculateDistance); if (nodePath == null) { return(null); } var path = new List <Vector2Int>(nodePath.ConvertAll((node) => node.Position)); return(path); }
private async Task BuildNodeGraph(float regionRadius, float bodyRadius, float toleranceRadius, CancellationToken cancellation) { this.regionRadius = Mathf.Max(regionRadius, 0); this.bodyRadius = Mathf.Max(bodyRadius, 0); cancellation.ThrowIfCancellationRequested(); // Build stencil. var stencil = await VisionStencil.BuildAsync(regionRadius, bodyRadius, toleranceRadius); cancellation.ThrowIfCancellationRequested(); // Build vision edges. int visionMaxOffset = Mathf.FloorToInt(regionRadius); var tasks = new List <Task>(); foreach (var node in nodes) { if (node is null) { continue; } var currentNode = node; var task = Task.Run(() => { // See all nodes around current one; add edge in graph for every visible node. foreach (var destinationPosition in Enumerables.InSegment2( currentNode.Position - visionMaxOffset * Vector2Int.one, currentNode.Position + visionMaxOffset * Vector2Int.one)) { cancellation.ThrowIfCancellationRequested(); if (!Enumerables.IsIndex(destinationPosition, nodes)) { continue; } var visionPath = stencil.GetVisionPath(currentNode.Position, destinationPosition); if (visionPath is null) { continue; } bool visible = true; foreach (var passedPosition in visionPath) { var passedNode = nodes[passedPosition.x, passedPosition.y]; if (passedNode is null) { visible = false; break; } } if (visible) { var destinationNode = nodes[destinationPosition.x, destinationPosition.y]; currentNode.AddVisible(destinationNode); } } }); tasks.Add(task); cancellation.ThrowIfCancellationRequested(); } await Task.WhenAll(tasks); cancellation.ThrowIfCancellationRequested(); // Build reach edges. tasks.Clear(); foreach (var node in nodes) { if (node is null) { continue; } var currentNode = node; var task = Task.Run(() => { // Try reach all nodes around current one; add edge in graph for every reachable node. var reachable = DijkstraDense.FindAllReachable(currentNode.AsVision, regionRadius); cancellation.ThrowIfCancellationRequested(); foreach (var nodeAndDistance in reachable) { var reachedPosition = nodeAndDistance.Key.Position; var reachedNode = nodes[reachedPosition.x, reachedPosition.y]; currentNode.AddReachable(reachedNode, nodeAndDistance.Value); } cancellation.ThrowIfCancellationRequested(); }); tasks.Add(task); cancellation.ThrowIfCancellationRequested(); } await Task.WhenAll(tasks); cancellation.ThrowIfCancellationRequested(); }