コード例 #1
0
        /// <summary>
        /// Called when the surface becomes available.
        /// </summary>
        /// <param name="delayedRequest">A request that was delayed until surface becomes available.</param>
        protected override void OnSurfaceAvailable(PathfindingRequest delayedRequest)
        {
            if (currentFace == null ||
                !AlchemyNavigationSystem.Current.ContainsFace(Layer, currentFace.source))
            {
                var ray = new Ray(position, Vector3.down);
                if (AlchemyNavigationSystem.Current.Raycast(ray, Layer, AreaMask, out var result))
                {
                    currentFace = new CachedFace(result.face);
                    position    = result.position;
                    ApplyPosition();
                }
                else
                {
                    Debug.LogWarning("Agent couldn't be placed on navigation surface.");
                    gameObject.SetActive(false);
                    return;
                }
            }

            if (delayedRequest != null)
            {
                CancelAllRequests();
                RequestPath(position, delayedRequest.endPosition, PathType, currentFace.source);
            }
            else if (IsPathWalking)
            {
                Vector3 destination = progress.pointPath[progress.pointsCount - 1];
                CancelAllRequests();
                RequestPath(position, destination, PathType, currentFace.source);
            }
        }
コード例 #2
0
    /**
     * Runs a pathfinding test on a simple world with a ] shape.
     */
    public bool RunPathfindingTest(bool validPath = true)
    {
        //Setup the world nodes
        worldSize  = 8;
        worldNodes = new Node[worldSize, worldSize];
        //Fill the world nodes array with default values
        for (int x = 0; x < 8; x++)
        {
            for (int y = 0; y < 8; y++)
            {
                Node newNode = new Node(x, y);
                newNode.SetBlocked(true);
                worldNodes[x, y] = newNode;
            }
        }
        worldNodes[1, 1].SetBlocked(false);
        worldNodes[2, 1].SetBlocked(false);
        worldNodes[3, 1].SetBlocked(false);
        worldNodes[4, 1].SetBlocked(false);
        worldNodes[4, 2].SetBlocked(false);
        worldNodes[4, 3].SetBlocked(false);
        worldNodes[4, 4].SetBlocked(!validPath);
        worldNodes[4, 5].SetBlocked(false);
        worldNodes[4, 6].SetBlocked(false);
        worldNodes[3, 6].SetBlocked(false);
        worldNodes[2, 6].SetBlocked(false);
        Log.PrintDebug("Created simple world for testing.");
        PathfindingRequest request = new PathfindingRequest();

        request.start_x = 1;
        request.start_y = 1;
        request.end_x   = 2;
        request.end_y   = 6;
        return(CalculatePath(request));
    }
コード例 #3
0
    private PathfindingRequest CreateNewRequest()
    {
        // Creates a new request object, with the destination being a random position on the map.

        int endX;
        int endY;

        while (true)
        {
            endX = Random.Range(0, Map.Width);
            endY = Random.Range(0, Map.Height);

            // Is this end point inside a wall?
            if (Map.Tiles[endX, endY] == true)
            {
                continue;
            }

            // Is this end point the same as the current position?
            if (this.X == endX && this.Y == endY)
            {
                continue;
            }

            // Passed all the conditions, end the loop.
            break;
        }

        // Create the request, with the callback method being UponPathCompleted.
        var request = PathfindingRequest.Create(X, Y, endX, endY, UponPathCompleted, currentPath);

        return(request);
    }
コード例 #4
0
    private static void Run()
    {
        // Runs on the thread.
        UnityEngine.Debug.Log("Running pathfinding multithread...");
        while (run)
        {
            if (!writing)
            {
                if (pending.Count == 0)
                {
                    Thread.Sleep(5);
                    continue;
                }

                PathfindingRequest request = pending.Dequeue();
                if (request.IsValid())
                {
                    watch.Reset();
                    watch.Start();

                    // Pathfind here.
                    List <Node> path = Pathfinding.Run(request.StartX, request.StartY, request.EndX, request.EndY, request.Layer);

                    acc++;

                    watch.Stop();
                    long elapsed = watch.ElapsedMilliseconds;
                    times.Add(elapsed);

                    if (times.Count > 100)
                    {
                        times.RemoveAt(0);
                    }

                    if (request.Done != null)
                    {
                        lock (hasPending)
                        {
                            hasPending.Remove(request.ID);
                        }
                        while (reading)
                        {
                            Thread.Sleep(10);
                        }
                        finished.Add(new KeyValuePair <UnityAction <List <Node> >, List <Node> >(request.Done, path));
                    }
                    else
                    {
                        lock (hasPending)
                        {
                            hasPending.Remove(request.ID);
                        }
                        UnityEngine.Debug.LogWarning("Wasted pathfinding (" + (path == null ? "NO PATH" : "PATH FOUND") + "), no receptor!");
                    }
                }
            }
        }
        UnityEngine.Debug.Log("Shutdown pathfinding multithread.");
    }
コード例 #5
0
    public void Start()
    {
        // Initialize the current path list.
        currentPath = new List <PNode>();

        // Create the current request.
        CurrentRequest = CreateNewRequest();
    }
コード例 #6
0
    /// <summary>
    /// Runs a pathfinding requests for a debug dummy path
    /// </summary>
    public void RequestDebugPath()
    {
        PathfindingRequest request = new PathfindingRequest();

        request.start_x = 4;
        request.start_y = 10;
        request.end_x   = 40;
        request.end_y   = 40;
        CalculatePath(request);
    }
コード例 #7
0
        public void PlotPath(Point destination)
        {
            if (IsPlottingPath)
            {
                CancelPathPlot();
            }
            var tp = base.TilePosition;
            PathfindingRequest req = new PathfindingRequest(tp.X, tp.Y, destination.X, destination.Y, PathCallback);

            realPathReq = JEngine.Pathfinding.Post(req);
        }
コード例 #8
0
    /*public static int Closest(List<PathNode> inNodes, Vector3 toPoint)
     * {
     *  int closestIndex = 0;
     *  float minDist = float.MaxValue;
     *  for(int i = 0; i < inNodes.Count; i++)
     *  {
     *      if(AStarHelper.Invalid(inNodes[i]))
     *          continue;
     *      float thisDist = Vector3.Distance(toPoint, inNodes[i].Position);
     *      if(thisDist > minDist)
     *          continue;
     *
     *      minDist = thisDist;
     *      closestIndex = i;
     *  }
     *
     *  if (minDist != float.MaxValue)
     *          return closestIndex;
     *          else
     *                  return -1;
     * }*/

    /*public static List<PathNode> GetSources()
     * {
     *      return sources;
     * }*/

    PathfindingRequest FindRequest(PathfindingRequest req)
    {
        foreach (PathfindingRequest pr in requests)
        {
            if (req.Id == pr.Id)
            {
                return(req);
            }
        }

        return(null);
    }
コード例 #9
0
    /// <summary>
    /// Adds the surround nodes to a source node, and sets their conditions.
    /// </summary>
    private void AddSurroundingNodes(ref List <Node> toCheckList, Node source, PathfindingRequest request)
    {
        //Get the adjacent nodes
        List <Node> adjacentNodes = GetAdjacentNodes(source);

        //Check each node individually
        //(secretly an embedded for loop which is a bit slow, but its only 4 long)
        for (int i = 0; i < adjacentNodes.Count; i++)
        {
            Node current = adjacentNodes[i];
            if (current.x == request.start_x && current.y == request.start_y)
            {
                continue;
            }
            //Ignore blocked nodes
            if (current.GetBlocked())
            {
                continue;
            }
            //In this case the node next has a parent node.
            //We need to check if by making source the parent node to current will make
            //a quicker path
            if (current.originNode != null && current.pathId == pathId)
            {
                //Our g cost will be the parent nodes gCost add 1
                float newGCost = current.originNode.gCost + 1;
                //Quicker to path through source
                if (newGCost < current.gCost)
                {
                    current.SetCosts(newGCost, current.hCost);
                    current.originNode = source;
                }
            }
            //In this case current is independant and has no parent
            //So we can add source as the parent instantly.
            else
            {
                //We come from source
                current.originNode = source;
                //We are 1 further from source from the start
                current.SetCosts(source.gCost + 1, QDistanceCalculation(current.x, current.y, request.end_x, request.end_y));
                //We are updated for this path
                current.pathId = pathId;
                //We need to check this
                if (!current.isChecked)
                {
                    toCheckList.Add(current);
                }
            }
        }
    }
コード例 #10
0
    public static bool Find(string ID, int x, int y, int ex, int ey, TileLayer layer, UnityAction <List <Node> > done)
    {
        if (!run)
        {
            if (done != null)
            {
                done.Invoke(null);
            }
            return(false);
        }

        if (pending.Count >= MAX_PENDING)
        {
            if (done != null)
            {
                done.Invoke(null);
            }
            return(false);
        }

        if (hasPending.Contains(ID))
        {
            return(false);
        }

        PathfindingRequest r = new PathfindingRequest()
        {
            StartX = x, StartY = y, EndX = ex, EndY = ey, Layer = layer, Done = done, ID = ID
        };

        if (r.IsValid())
        {
            writing = true;
            lock (hasPending)
            {
                hasPending.Add(ID);
            }
            pending.Enqueue(r);
            writing = false;
            return(true);
        }
        else
        {
            if (done != null)
            {
                done.Invoke(null);
            }
            return(false);
        }
    }
コード例 #11
0
    public List <PathNode> RequestPath(PathfindingRequest req, ref bool result)
    {
        List <PathNode> pathResult = null;

        //float time1 = 0;
        //float time2 = 0;

        //DateTime dt1 = DateTime.Now;
        //DateTime dt2 = DateTime.Now;
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();

        if (FindRequest(req) != null && FpsCounter.pathfindingsCounter <= maxPathFindingPerSecond)
        {
            FpsCounter.pathfindingsCounter++;

            requests.Remove(req);

            result = true;

            sw.Start();
            pathResult = GetPath(req.Start, req.End);
            sw.Stop();
        }
        else if (requests.Count == 0 && FpsCounter.pathfindingsCounter <= maxPathFindingPerSecond)
        {
            FpsCounter.pathfindingsCounter++;

            result = true;

            sw.Start();
            pathResult = GetPath(req.Start, req.End);
            sw.Stop();
        }
        else
        {
            result = false;

            requests.Add(req);

            pathResult = null;
        }

        if (result)
        {
            //Debug.Log ("Pathfinding time: " + (sw.ElapsedMilliseconds) + " ms");
            FpsCounter.pathfindingTime = sw.ElapsedMilliseconds;
        }

        return(pathResult);
    }
コード例 #12
0
    /// <summary>
    /// Should only be called from unity events such as Start or Update.
    /// The requests are actually scheduled at the end of LateUpdate.
    /// Requests are returned (once completed) before Update.
    /// For example, a request is made in frame 0 in the Update thread. The path takes 1 frame to calculate.
    /// Then, in frame 2, before any calls to Update, the return method is called.
    /// </summary>
    /// <param name="request"></param>
    public void Enqueue(PathfindingRequest request)
    {
        if (request == null)
        {
            return;
        }

        if (!pending.Contains(request))
        {
            pending.Add(request);
        }
        else
        {
            Debug.LogWarning("That pathfinding request was already submitted.");
        }
    }
コード例 #13
0
    public void Update()
    {
        if (CurrentRequest != null)
        {
            return;
        }
        if (currentPath == null)
        {
            return;
        }

        movementTimer += Time.deltaTime;

        PNode previousNode = currentPath[previousNodeIndex];
        PNode nextNode     = currentPath[previousNodeIndex + 1];
        float dst          = GetDistance(previousNode, nextNode);

        float progress = Mathf.Clamp01((movementTimer * MovementSpeed) / dst);

        if (progress == 1f)
        {
            // Update our position to the position we just reached.
            this.X = nextNode.X;
            this.Y = nextNode.Y;

            if (previousNodeIndex == currentPath.Count - 2)
            {
                // Reached the end of the path. Request a new path...
                // Setting current request also stops us from moving, see the first line of Update.
                CurrentRequest = CreateNewRequest();
            }
            else
            {
                previousNodeIndex++;
                movementTimer = 0f;
            }
        }

        // Set position. Note that PNode can be used as a Vector. Useful and clean.
        transform.position = Vector2.Lerp(previousNode, nextNode, progress);
        transform.Translate(0f, 0f, -1f); // Move towards the camera.
    }
コード例 #14
0
    protected override void Update(float processingTime)
    {
        if (subsystemQuery.Keys.Count <= 0)
        {
            //Run queued paths
            if (pathRequests.Count == 0)
            {
                return;
            }
            //Get the request
            PathfindingRequest request = pathRequests[0];
            pathRequests.RemoveAt(0);
            //Run the path
            CalculatePath(request);
            return;
        }

        //Get the query
        string queryName = subsystemQuery.Keys.ElementAt(0);
        object queryData = subsystemQuery[queryName];

        //Execute queries
        switch (queryName)
        {
        case "SetWorldConditions":
            SetWorldConditions();
            break;

        case "DebugPath":
            RequestDebugPath();
            break;

        default:
            Log.PrintError($"Unrecognised query [{queryName}] in networkGenerator, deleting");
            break;
        }

        subsystemQuery.Remove(queryName);
    }
コード例 #15
0
    /// <summary>
    /// Adds the initial nodes to check and updates them to what we need.
    /// </summary>
    /// <param name="nodeChecklist"></param>
    private void SetupInitialConditions(ref List <Node> nodeChecklist, PathfindingRequest request)
    {
        Node firstNode = worldNodes[request.start_x, request.start_y];

        //Setup the first node
        firstNode.SetCosts(0, QDistanceCalculation(request.start_x, request.start_y, request.end_x, request.end_y));
        firstNode.originNode = null;
        firstNode.pathId     = pathId;
        firstNode.isChecked  = true;
        List <Node> firstNodes = GetAdjacentNodes(firstNode);

        foreach (Node node in firstNodes)
        {
            //The node is being worked on this path
            node.pathId = pathId;
            //We connect to the main node simply
            node.originNode = firstNode;
            //Calculate the costs.
            node.SetCosts(1, QDistanceCalculation(node.x, node.y, firstNode.x, firstNode.y));
            //Add it
            nodeChecklist.Add(node);
        }
    }
コード例 #16
0
    private void UponPathCompleted(PathfindingResult result, List <PNode> path)
    {
        // This means that the request has completed, so it is important to dispose of it now.
        CurrentRequest.Dispose();
        CurrentRequest = null;


        // Check the result...
        if (result != PathfindingResult.SUCCESSFUL)
        {
            // Debug.LogWarning("Pathfinding failed: " + result);

            // Most likely is that it was impossible to find a route from the start to end.
            // Request a new path then, hopefully this time it won't be a failure.
            CurrentRequest = CreateNewRequest();
        }
        else
        {
            // Apply the path that was just calculated.
            currentPath       = path;
            previousNodeIndex = 0;
            movementTimer     = 0f;
        }
    }
コード例 #17
0
        /// <summary>
        /// Calculates the face path.
        /// </summary>
        /// <param name="request">The request to calculate.</param>
        /// <param name="surface">The surface to be used for calculations.</param>
        /// <returns>The face path in the form of a list.</returns>
        public static List <IImmutableFace> FindFacePath(PathfindingRequest request, NavigationSurface surface)
        {
            int  agentAreaMask = request.areaMask;
            Face start;

            if (request.startFace != null)
            {
                start = (Face)request.startFace;
            }
            else
            {
                start = surface.FindFirstFaceUnderPosition(request.startPosition, agentAreaMask);
            }
            Face end = surface.FindFirstFaceUnderPosition(request.endPosition, agentAreaMask);

            if (start == null || end == null)
            {
                //Debug.Log((start == null) + " " +  (end == null) + " null null FaceAStar");
                return(null);
            }
            else if (start == end)
            {
                //Debug.Log("start == end FaceAStar");
                return(new List <IImmutableFace>()
                {
                    start
                });
            }
            else
            {
                //Debug.Log("process FaceAStar");
                var process = new FaceAStar(start, end, agentAreaMask);
                process.FindFacePath();
                return(process.result);
            }
        }
コード例 #18
0
    public List<PathNode> RequestPath(PathfindingRequest req, ref bool result)
    {
        List<PathNode> pathResult = null;

        //float time1 = 0;
        //float time2 = 0;

        //DateTime dt1 = DateTime.Now;
        //DateTime dt2 = DateTime.Now;
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();

        if (FindRequest(req) != null && FpsCounter.pathfindingsCounter <= maxPathFindingPerSecond)
        {
            FpsCounter.pathfindingsCounter++;

            requests.Remove(req);

            result = true;

            sw.Start();
            pathResult = GetPath(req.Start, req.End);
            sw.Stop();
        }
        else if (requests.Count == 0 && FpsCounter.pathfindingsCounter <= maxPathFindingPerSecond)
        {
            FpsCounter.pathfindingsCounter++;

            result = true;

            sw.Start();
            pathResult = GetPath(req.Start, req.End);
            sw.Stop();
        }
        else
        {
            result = false;

            requests.Add(req);

            pathResult = null;
        }

        if (result)
        {
            //Debug.Log ("Pathfinding time: " + (sw.ElapsedMilliseconds) + " ms");
            FpsCounter.pathfindingTime = sw.ElapsedMilliseconds;
        }

        return pathResult;
    }
コード例 #19
0
    /*public static int Closest(List<PathNode> inNodes, Vector3 toPoint)
    {
        int closestIndex = 0;
        float minDist = float.MaxValue;
        for(int i = 0; i < inNodes.Count; i++)
        {
            if(AStarHelper.Invalid(inNodes[i]))
                continue;
            float thisDist = Vector3.Distance(toPoint, inNodes[i].Position);
            if(thisDist > minDist)
                continue;

            minDist = thisDist;
            closestIndex = i;
        }

        if (minDist != float.MaxValue)
            return closestIndex;
        else
            return -1;
    }*/
    /*public static List<PathNode> GetSources()
    {
        return sources;
    }*/
    PathfindingRequest FindRequest(PathfindingRequest req)
    {
        foreach (PathfindingRequest pr in requests)
            if (req.Id == pr.Id)
                return req;

        return null;
    }
コード例 #20
0
 public PathfindingRequest(PathfindingRequest _ref)
 {
     this.start = _ref.start;
     this.end = _ref.end;
     this.id = _ref.id;
 }
コード例 #21
0
    /// <summary>
    /// Calculates the path.
    /// We can do it all in 1 go, this system is on a seperate thread so it doesn't matter too much if we take a while.
    /// This is probably a pretty ineffecient implementation but its on a seperate thread, gets the job done and isn't too critical for the project.
    /// </summary>
    /// <param name="request"></param>
    public bool CalculatePath(PathfindingRequest request)
    {
        pathId++;
        //The list of nodes that can be searched
        //Everything in this list should have updated costs values before going in
        //since we don't reset and recaclulate every time so the old path values will
        //be carried over otherwise.
        List <Node> searchNodes = new List <Node>();
        //Cache the end node because its quicker than checking list every time
        Node targetNode = worldNodes[request.end_x, request.end_y];

        //Calculate initial nodes (The ones adjacent)
        SetupInitialConditions(ref searchNodes, request);
        //Cool lets just keep searching until we run out of things to search
        //If we have to search more than X nodes, just assume its impossible.
        int       sanity = 20000;
        Stopwatch timer  = new Stopwatch();

        timer.Start();
        while (sanity > 0 && searchNodes.Count > 0)
        {
            sanity--;
            //Might be a way with cachine to make this faster, this is quite slow :(
            //We could use a sorted list, binary search and insertion in order?#
            //Would be tons faster
            //(We do all this mini optimisations then have this as super slow!)
            int   lowestIndex = 0;
            float lowestCost  = searchNodes[lowestIndex].GetTotalCost();
            for (int i = 1; i < searchNodes.Count; i++)
            {
                float testCost = searchNodes[i].GetTotalCost();
                if (testCost < lowestCost)
                {
                    lowestCost  = testCost;
                    lowestIndex = i;
                }
            }
            //We know the node to search now
            Node testingNode = searchNodes[lowestIndex];
            //Console.WriteLine($"Checking: {testingNode.x}, {testingNode.y} with cost: {testingNode.GetTotalCost()}");
            //Have we reached the end?
            if (testingNode == targetNode)
            {
                List <Node> quickestPath = testingNode.GetRecursiveNodes();
                List <Turf> pathTurfs    = new List <Turf>();
                Log.PrintDebug($"Found path length: {quickestPath.Count}");
#if !UNITY_INCLUDE_TESTS
                foreach (Node node in quickestPath)
                {
                    Turf locatedBase = LevelGenerator.current.turfs[node.x, node.y];
                    pathTurfs.Add(locatedBase);
                }
#endif
                Path finalPath = new Path();
                finalPath.calculatedRoute = pathTurfs;
                request.CompletePath(finalPath);
                timer.Stop();
                Log.PrintDebug($"Found path in {timer.ElapsedMilliseconds}ms");
                return(true);
            }
            //Add surrounding nodes
            AddSurroundingNodes(ref searchNodes, testingNode, request);
            //Block it from being re-added
            testingNode.isChecked = true;
            //Thats all the checking we needed to do
            searchNodes.Remove(testingNode);
        }
        //No path found
        request.FailPath();
        Log.PrintDebug("No path was found");
        Log.PrintDebug($"Failed to find path in {timer.ElapsedMilliseconds}ms");
        return(false);
    }
コード例 #22
0
 public PathfindingRequest(PathfindingRequest _ref)
 {
     this.start = _ref.start;
     this.end   = _ref.end;
     this.id    = _ref.id;
 }