0
\$\begingroup\$

Hellow~

So for a bit of context: i'm currently working on a RTS (way above may league) which already has a level editor and a node grid which maps the terrain, i previously make a navigation system with A* as explainned by Sebastian Lague in his tutorial series about the topic, but then i run into a problem when running with multiple units (not the point here: but never manage to find each unit cluster within the selection), so i change it into a navmesh mapping which if made dynamic by assigning navmesh obstacles to the unwalkable nodes (the frame after the creation of the node grid)

Now i want to use the node grid basically to check if the target node and the start node share the same node cluster. But here is the thing: i can't assign the needed index to the nodes as i expected.

I've been trying adapting code from this post, but didn't quite make it. Now i have this one, which i think could achieve something but still gets me a invalid operation exception:

public const int UNWALKABLE_ISLAND = 999;

public static void SetIslands(ref WorldGrid _worldGrid) {
    int width = _worldGrid.nodeGrid.GetLength(0);
    int height = _worldGrid.nodeGrid.GetLength(1);

    bool[,] visited = new bool[width, height];

    int clusterCount = 0;

    for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++)
        {
            if (visited[x, y]) { continue; } else {
                List<Node> cluster = new List<Node>() {
                    _worldGrid.nodeGrid[x, y]
                };

                foreach (var node in cluster) {
                    if (node.isWalkable)
                    {
                        visited[node.X, node.Y] = true;
                        node.SetIslandIndex(clusterCount);
                        cluster.AddRange(_worldGrid.GetNeighbours8D(node));
                    }
                    else
                    {
                        cluster.Remove(node);
                    }
                }

                clusterCount++;
            }
        }
    }
}

The error:

InvalidOperationException: Collection was modified; enumeration operation may not execute. System.ThrowHelper.ThrowInvalidOperationException (System.ExceptionResource resource) (at<437ba245d8404787b9fbab9b439ac908>:0) System.Collections.Generic.List1+Enumerator[T].MoveNextRare() (at<437ba245d8404787b9fbab9b439ac908>:0) System.Collections.Generic.List1+Enumerator[T].MoveNext() (at<437ba245d8404787b9fbab9b439ac908>:0) Pathfinding.SetIslands (WorldGrid& _worldGrid) (at Assets/Pathfinding.cs: 25) WorldGrid.CreateNodeGrid() (at Assets/WorldGrid:80) WorldGrid+d_12.MoveNext() (at Assets/WorldGrid.cs:42) UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, Sustem.IntPtr returnValueAddress) (at<437ba245d8404787b9fbab9b439ac908>:0) UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)

My node class contains an int that should hold the cluster index, which will be using for the request check. (the code its based from this youtube video)

Right now i'm trying to understand the spectral clustering stuff, i've been told it could help.

I hope you can help an animator in need with some pointers.

Cheers :3

*Oh!, I also tried reading the nav agent path end coordinate for comparison, but it ended up becoming a huge mess for me.

\$\endgroup\$
8
  • \$\begingroup\$ What line throws an invalid operation exception? What message comes along with the exception? \$\endgroup\$ – DMGregory Nov 26 '20 at 18:29
  • \$\begingroup\$ Hi!, the error is the following: imghub.io/i/sX9vk, as for the line 25, it corresponds with foreach (var node in cluster) {. Line 80 in WorldGrid.cs is the calling of the method Pathfinding.SetIslands(ref Instance); \$\endgroup\$ – Frame Matt Nov 26 '20 at 18:34
  • \$\begingroup\$ That belongs in the text of your question, not in an image hosted off-site tucked away in the comments. Since this is a standard exception, is it safe to assume you started by searching StackOverflow for this error and applying the answers there to your case? I notice for example that foreach occurs nowhere in the code you're modifying. \$\endgroup\$ – DMGregory Nov 26 '20 at 18:42
  • \$\begingroup\$ Sorry about that, I'll add the error to the main question for reading, yes i did try that. At some point I had a dictionary<int,List<Node>> to sort all the clusters but it didn't work like i thought. Nevertheless i didn't spend that much time looking out for more examples on exceptions, so will get back at it just in case. Cheers \$\endgroup\$ – Frame Matt Nov 26 '20 at 18:55
  • \$\begingroup\$ What your error basically wants to tell you: don't touch your collection (add/ remove) in the foreach. \$\endgroup\$ – Zibelas Nov 27 '20 at 16:53
0
\$\begingroup\$

Woot!

I manage to set up island indexes by flood filling the nodes, in different manner as i was attempting. Here is the code for further reference:

private static int clusterIndex = 0;
private static bool[,] visited;

public static void FloodIslands()
{
    int width = WorldGrid.Instance.nodeGrid.GetLength(0);
    int height = WorldGrid.Instance.nodeGrid.GetLength(1);
    visited = new bool[width, height];

    for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++)
        {
            if (visited[x, y] || !WorldGrid.Instance.nodeGrid[x,y].isWalkable && !visited[x, y]) { continue; }
            else {
                SearchCluster(x, y, width, height, clusterIndex);
                clusterIndex++;
            }
        }
    }
}

private static void SearchCluster(int _x, int _y, int _width, int _height, int _desiredIndex) {
    if (_x < 0 || _y < 0 || _x >= _width || _y >= _height || 
        WorldGrid.Instance.nodeGrid[_x, _y].isWalkable == false ||
        WorldGrid.Instance.nodeGrid[_x,_y].IslandIndex == _desiredIndex) {
        return;
    }

    Node node = WorldGrid.Instance.nodeGrid[_x, _y];

    node.SetIslandIndex(_desiredIndex);
    visited[node.X, node.Y] = true;

    SearchCluster(_x + 1, _y, _width, _height, _desiredIndex);
    SearchCluster(_x - 1, _y, _width, _height, _desiredIndex);
    SearchCluster(_x, _y + 1, _width, _height, _desiredIndex);
    SearchCluster(_x, _y - 1, _width, _height, _desiredIndex);
}

This way i didn't had to deal with the wierd collection exceptions.

*DMGregory thank you so much for the tip, even though i couldn't make it work around the list, it did push me to look for alternatives, until i hit this reference (a youtube video from Nick White).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.