Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

(Solved) Problems with working with multiple lists

Discussion in 'Scripting' started by LetsStartSomeSeriousCoding, Oct 30, 2018.

  1. LetsStartSomeSeriousCoding

    LetsStartSomeSeriousCoding

    Joined:
    Apr 2, 2017
    Posts:
    33
    So... I'm working at a Pathfinding project, just for fun, and I need to work with a bunch of lists that contain nodes. I started with built-in arrays, and they work perfectly, it's only a little hard to get started. But now, Since I need to have a dynamic list so I can remove or add things easily (+ I need an ordered list to), I decided to use the List collection of Unity.
    So as I said, I'm working at a pathfinding code, but when the program reaches some lines of code, it becomes so messy that I can't even tell you exactly what's happening.
    Code (CSharp):
    1.  public IEnumerator getPath(Vector3 start, Vector3 end)
    2.     {
    3.         List<Node> path = new List<Node>();
    4.         List<Node> toSee = new List<Node>(circNodes(start));
    5.         List<Node> saw = new List<Node>();
    6.         List<Node> endNodes = new List<Node>(circNodes(end));
    7.         List<Node> startNodes = new List<Node>(circNodes(start));
    8.         Node node = bestNode(toSee, start, end);
    9.         Debug.Log(node.x.ToString() + "," + node.z.ToString());
    10.         bool c1 = true;
    11.         bool waiting = false;
    12.         while (c1)
    13.         {
    14.             while (waiting)
    15.             {
    16.                 node = bestNode(toSee, start, end);
    17.                 toSee.Remove(node);
    18.                 saw.Add(node);
    19.  
    20.  
    21.                 foreach (Node n in node.adiacent_nodes)
    22.                 {
    23.                     if (!saw.Contains(n) && !toSee.Contains(n))
    24.                     {
    25.                         n.from = node;
    26.                         toSee.Add(node);
    27.                     }
    28.                 }
    29.  
    30.  
    31.                 if (endNodes.Contains(node))
    32.                 {
    33.                     c1 = false;
    34.                 }
    35.                 main.log(node.x.ToString() + "," + node.z.ToString());
    36.                 waiting = false;
    37.                 foreach (Node n in toSee)
    38.                 {
    39.                     Debug.Log("toSee: " + n.x + "," + n.z);
    40.                 }
    41.                 foreach (Node n in saw)
    42.                 {
    43.                     Debug.Log("saw: " + n.x + "," + n.z);
    44.                 }
    45.             }
    46.             if (Input.GetKeyDown(KeyCode.Space))
    47.             {
    48.                 waiting = true;
    49.             }
    50.             yield return 0;
    51.         }
    52.         Debug.Log("FINALLY");
    53.         bool c2 = false;
    54.         path.Add(node);
    55.         while (c2)
    56.         {
    57.             node = node.from;
    58.             path.Add(node);
    59.             if (startNodes.Contains(node))
    60.             {
    61.                 c2 = false;
    62.             }
    63.             while (!Input.GetKey(KeyCode.Space))
    64.             {
    65.                 yield return null;
    66.             }
    67.         }
    68.         path.Reverse();
    69.         yield return 0;
    70.  
    71.     }
    In particular, the lines that cause me problems are these:
    Code (CSharp):
    1. foreach (Node n in node.adiacent_nodes)
    2.                 {
    3.                     if (!saw.Contains(n) && !toSee.Contains(n))
    4.                     {
    5.                         n.from = node;
    6.                         toSee.Add(node);
    7.                     }
    8.                 }
    Basically, I'm getting the "best" node through a bunch of nodes contained in the toSee list. After I do that, I remove that node from the list, because I've already evaluated it. Then, I want to add every node near to the node I'm evaluating to the toSee list, and that's the part that's not working. If I remove completely those lines, it works perfectly.
    Full classes:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System.Threading;
    5. using System;
    6.  
    7. public class Pathfinding
    8. {
    9.  
    10.     public Node[] nodes;
    11.  
    12.     private int x_;
    13.     private int z_;
    14.     private int size;
    15.     public int log_0;
    16.     public int count;
    17.  
    18.     public Pathfinding(int x_, int z_)
    19.     {
    20.         count = 0;
    21.         this.x_ = x_;
    22.         this.z_ = z_;
    23.         size = ((4 * x_ * z_));
    24.         nodes = new Node[size];
    25.         int output = 0;
    26.         int x = -x_;
    27.         int z = -z_;
    28.         for (int a = 0; a < size; a++)
    29.         {
    30.             Node node = new Node(x, z);
    31.             nodes[a] = node;
    32.             x += 1;
    33.             if (x > x_)
    34.             {
    35.                 x = -x_;
    36.                 z += 1;
    37.             }
    38.             output++;
    39.             Debug.Log(output.ToString()+"/"+size.ToString());
    40.         }
    41.         new Thread(() =>
    42.         {
    43.             getAdiacentNodes(0,6084);
    44.         }).Start();
    45.         new Thread(() =>
    46.         {
    47.             getAdiacentNodes(6084, 12168);
    48.         }).Start();
    49.         new Thread(() =>
    50.         {
    51.             getAdiacentNodes(12168, 18252);
    52.         }).Start();
    53.         new Thread(() =>
    54.         {
    55.             getAdiacentNodes(18252, 24336);
    56.         }).Start();
    57.     }
    58.     public Node getNode(int x, int z)
    59.     {
    60.         int a = 2 * x_+1;
    61.         int b = z + z_;
    62.         int c = x + x_;
    63.         int d = b * a;
    64.         try
    65.         {
    66.             return nodes[c + d];
    67.         }
    68.         catch (IndexOutOfRangeException)
    69.         {
    70.             Debug.Log("no Node t: " + x.ToString() + "," + z.ToString());
    71.             return null;
    72.         }
    73.     }
    74.     public void getAdiacentNodes(int start, int end)
    75.     {
    76.         for(int f = start; f < end; f++)
    77.         {
    78.             for (int a = 0; a < 8; a++)
    79.             {
    80.                 count++;
    81.                 int x = 0;
    82.                 int z = 0;
    83.                 switch (a)
    84.                 {
    85.                     case 0:
    86.                         x = -1;
    87.                         z = -1;
    88.                         break;
    89.                     case 1:
    90.                         x = -1;
    91.                         z = 0;
    92.                         break;
    93.                     case 2:
    94.                         x = -1;
    95.                         z = 1;
    96.                         break;
    97.                     case 3:
    98.                         x = 0;
    99.                         z = -1;
    100.                         break;
    101.                     case 4:
    102.                         x = 0;
    103.                         z = 1;
    104.                         break;
    105.                     case 5:
    106.                         x = 1;
    107.                         z = -1;
    108.                         break;
    109.                     case 6:
    110.                         x = 1;
    111.                         z = 0;
    112.                         break;
    113.                     case 7:
    114.                         x = 1;
    115.                         z = 1;
    116.                         break;
    117.                 }
    118.                 nodes[f].adiacent_nodes[a] = getNode(nodes[f].x + x, nodes[f].z + z);
    119.             }
    120.             main.log(count.ToString() + "/" + (size*8).ToString());
    121.         }
    122.     }
    123.     public Node[] circNodes(Vector3 v) {
    124.         int x = (int) Mathf.Floor(v.x);
    125.         int z = (int) Mathf.Floor(v.z);
    126.         return new Node[] { getNode(x, z), getNode(x + 1, z), getNode(x, z + 1), getNode(x + 1, z + 1) };
    127.     }
    128.     public IEnumerator getPath(Vector3 start, Vector3 end)
    129.     {
    130.         List<Node> path = new List<Node>();
    131.         List<Node> toSee = new List<Node>(circNodes(start));
    132.         List<Node> saw = new List<Node>();
    133.         List<Node> endNodes = new List<Node>(circNodes(end));
    134.         List<Node> startNodes = new List<Node>(circNodes(start));
    135.         Node node = bestNode(toSee, start, end);
    136.         Debug.Log(node.x.ToString() + "," + node.z.ToString());
    137.         bool c1 = true;
    138.         bool waiting = false;
    139.         while (c1)
    140.         {
    141.             while (waiting)
    142.             {
    143.                 node = bestNode(toSee, start, end);
    144.                 toSee.Remove(node);
    145.                 saw.Add(node);
    146.  
    147.                 foreach (Node n in node.adiacent_nodes)
    148.                 {
    149.                     if (!saw.Contains(n) && !toSee.Contains(n))
    150.                     {
    151.                         n.from = node;
    152.                         toSee.Add(node);
    153.                     }
    154.                 }
    155.  
    156.                 if (endNodes.Contains(node))
    157.                 {
    158.                     c1 = false;
    159.                 }
    160.                 main.log(node.x.ToString() + "," + node.z.ToString());
    161.                 waiting = false;
    162.                 foreach (Node n in toSee)
    163.                 {
    164.                     Debug.Log("toSee: " + n.x + "," + n.z);
    165.                 }
    166.                 foreach (Node n in saw)
    167.                 {
    168.                     Debug.Log("saw: " + n.x + "," + n.z);
    169.                 }
    170.             }
    171.             if (Input.GetKeyDown(KeyCode.Space))
    172.             {
    173.                 waiting = true;
    174.             }
    175.             yield return 0;
    176.         }
    177.         Debug.Log("FINALLY");
    178.         bool c2 = false;
    179.         path.Add(node);
    180.         while (c2)
    181.         {
    182.             node = node.from;
    183.             path.Add(node);
    184.             if (startNodes.Contains(node))
    185.             {
    186.                 c2 = false;
    187.             }
    188.             while (!Input.GetKey(KeyCode.Space))
    189.             {
    190.                 yield return null;
    191.             }
    192.         }
    193.         path.Reverse();
    194.         yield return 0;
    195.  
    196.     }
    197.     public float value(Node n, Vector3 start, Vector3 end)
    198.     {
    199.         Vector3 v3 = new Vector3(n.x, 0, n.z);
    200.         return Vector3.Distance(v3, start) + Vector3.Distance(v3, end);
    201.     }
    202.     public Node bestNode(List<Node> list, Vector3 start, Vector3 end)
    203.     {
    204.         Node best = list[0];
    205.         foreach (Node n in list)
    206.         {
    207.             if (value(n, start, end) < value (best, start, end))
    208.             {
    209.                 best = n;
    210.             }
    211.         }
    212.         return best;
    213.     }
    214. }
    215.  
    216.  
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Node{
    6.  
    7.     public int x;
    8.     public int z;
    9.  
    10.     public Node from;
    11.     public Node[] adiacent_nodes;
    12.  
    13.     public Node(int x, int z)
    14.     {
    15.         adiacent_nodes = new Node[8];
    16.         this.x = x;
    17.         this.z = z;
    18.     }
    19. }
    20.  
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class main : MonoBehaviour {
    6.  
    7.     public static bool running;
    8.  
    9.     void Start () {
    10.         running = true;
    11.     }
    12.     public static void log(string s)
    13.     {
    14.         Debug.Log(s);
    15.     }
    16. }
    17.  
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class braga : MonoBehaviour{
    6.  
    7.     public int k;
    8.     public GameObject trgt;
    9.     public Vector3 target;
    10.     public float speed;
    11.     public int x;
    12.     public int z;
    13.     public Pathfinding pf;
    14.  
    15.     void Start()
    16.     {
    17.         pf = new Pathfinding(x, z);
    18.     }
    19.  
    20.     void Update()
    21.     {
    22.         if (Input.GetKeyDown(KeyCode.W))
    23.         {
    24.             target = trgt.transform.position;
    25.             StartCoroutine(pf.getPath(transform.position, target));
    26.         }
    27.         if (Input.GetKeyDown(KeyCode.C))
    28.         {
    29.             foreach(Node n in pf.getNode(0, 0).adiacent_nodes)
    30.             {
    31.                 Debug.Log(n.x.ToString() + "," + n.z.ToString());
    32.             }
    33.         }
    34.     }
    35.  
    36. }
    37.  
    I've forgot to write down the actual problem, I'm a genious xD
    Instead of working as it should, it adds to the toSee list the node I have just removed from that list. But not only 1 time, it adds like 10 copies of the same node to that list, even if I'm clearly checking if the node is not in the "saw" list. The "saw" list keeps adding that node, multiple times, at every iteration.
    By the way, i previously added some Debug.log to show me different values, like the nodes contained in the "adiacent_nodes" list. And those nodes are the nodes they are meant to be,no problems.
     
    Last edited: Oct 30, 2018
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,599
    This has nothing to do with lists. This has to do with the fundamental differences between a reference type and a value type in C#. There's a ton of really good explanations out there so I won't even try to begin to explain it, but googling for "difference between a reference and value type" will get you started.

    Take a look through that, understand what parts of your code are using value types and what parts are using reference types, and it will enable you to reason clearly about what you are attempting to do.
     
  3. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,186
    To expand on what @Kurt-Dekker is saying, you'd get the same thing with
    array1 = array2;
    and
    gameObjectA = gameObjectB



    This is the kind of problem where you're best of sitting down with a debugger and stepping through the code to see what's happening. I'd suggest looking up a debugger tutorial for your IDE (Visual Studio, Visual Studio Code, Rider, MonoDevelop). and figure out how to use it. That'll help you a lot both with figuring out this issue, and in the future.
     
  4. LetsStartSomeSeriousCoding

    LetsStartSomeSeriousCoding

    Joined:
    Apr 2, 2017
    Posts:
    33
    Ok so I'm a little pissed. After debugging and doing things for a day I found out the problem:
    Code (CSharp):
    1. foreach (Node n in node.adiacent_nodes)
    2.                 {
    3.                     if (!saw.Contains(n) && !toSee.Contains(n))
    4.                     {
    5.                         n.from = node;
    6.                         toSee.Add(node);
    7.                     }
    8.                 }
    As you see, instead of adding the node "n", I'm adding the node "node".
     
    Last edited: Oct 31, 2018
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,599
    You are simply working through the Six Stages of Debugging:

    1. That can’t happen.
    2. That doesn’t happen on my machine.
    3. That shouldn’t happen.
    4. Why does that happen?
    5. Oh, I see.
    6. How did that ever work?

    Well congratulations on finding this bug... now... Let's start some serious coding! :)
     
  6. LetsStartSomeSeriousCoding

    LetsStartSomeSeriousCoding

    Joined:
    Apr 2, 2017
    Posts:
    33
    Yeah, that's actually what just happened xD
     
    Kurt-Dekker likes this.