Esempio n. 1
0
        // 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();
        }