Search Unity

Confused between a stuct and a class(Flood fill not working when class)

Discussion in 'Scripting' started by Filtiarn_, Jan 31, 2015.

  1. Filtiarn_

    Filtiarn_

    Joined:
    Jan 24, 2013
    Posts:
    173
    Hi I'm confused why my floodfill and pathfinding wont work If I change my GridNode from a struct to a class. Information Below, I just want to understand why this is. I never really used struts before this so its new. I looked on google but I think someone looking at my code and giving me info would be the best way to learn why this is happing. I know this can be a lot of code so thanks for your time.

    I create my grid nodes like this.
    public List<GridNode[,]> gridNodes; //Its a list of a list of multidimensional array gridnodes so I can have grid nodes on different floors so I can path find to different floors(works).

    for (int i = 0; i < layers.Count; ++I)
    {
    gridNodes.Add(newGridNode[width,length]);
    }

    I set values of a gridNode like this.

    Nested For Loops
    {
    GridNode newGridNode = newGridNode(k, newVector3((i * nodeSize), layers[k].positionY, (j * nodeSize)), newVector2(i, j), initalCost, true);

    //Raycast for Height
    //Raycast for Position

    gridNodes[k][i, j] = newGridNode;
    }




    Code (CSharp):
    1. using UnityEngine;
    2. sing System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public struct GridNode
    6. {
    7.     public int layer;
    8.     public Vector3 position;
    9.     public Vector2 gridNodeIndex;
    10.     public GridNode[] gridNodesNeighbors;
    11.     public float cost;
    12.     public bool isTraversable;
    13.     public bool render;
    14.     public enum TileType {none,walk,attack,heal,skill}
    15.     public TileType tileType;
    16.    
    17.     public GridNode(int layer,Vector3 position, Vector2 gridNodeIndex,float cost,bool isTraversable)
    18.     {
    19.         this.layer = layer;
    20.         this.position = position;
    21.         this.gridNodeIndex = gridNodeIndex;
    22.         this.cost = cost;
    23.         this.isTraversable = isTraversable;
    24.         this.gridNodesNeighbors = new GridNode[0];
    25.         this.render = false;
    26.         this.tileType = TileType.none;
    27.     }
    28.    
    29.     public static bool operator == (GridNode first,GridNode second)
    30.     {
    31.         if (first.gridNodeIndex == second.gridNodeIndex && first.layer == second.layer)
    32.             return true;
    33.         return false;
    34.     }
    35.  
    36.     public static bool operator != (GridNode first,GridNode second)
    37.     {
    38.         if (first.gridNodeIndex == second.gridNodeIndex && first.layer == second.layer)
    39.             return false;
    40.         return true;
    41.     }
    42. }
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Threading;
    5.  
    6.  
    7. public class Seeker : MonoBehaviour
    8. {
    9.     public Transform target;
    10.     public bool seekPath;
    11.     public bool eightConnections;
    12.     public bool drawGizmos;
    13.    
    14.     Path path = new Path();
    15.     List<Expansion> open;
    16.     HashSet<GridNode> closed;
    17.     GridNode startingNode, targetNode;
    18.     Expansion best;
    19.     List<bool[,]> visited;
    20.  
    21.     float costToGoal;
    22.     float costToNextNode;
    23.     float costFromStart;
    24.  
    25.     enum FloodFillType {walk, attack, heal, skill}
    26.     FloodFillType floodFillType;
    27.     int floodFillDistance;
    28.     int floodFillCurrentDistance;
    29.  
    30.     public Path SearchPath(Vector3 startingPosition, Vector3 targetPosition)
    31.     {
    32.         open = new List<Expansion> ();
    33.         closed = new HashSet<GridNode> ();
    34.         startingNode = FindClosestGridNode(startingPosition);
    35.         targetNode = FindClosestGridNode(targetPosition);
    36.         best = new Expansion(startingNode,null,0,0);
    37.         best.current = startingNode;
    38.         open.Add(best);
    39.  
    40.         visited = new List<bool[,]>();
    41.         for (int i = 0; i < GridGraph.instance.layers.Count; ++i)
    42.             visited.Add(new bool[GridGraph.instance.width, GridGraph.instance.length]);
    43.    
    44.         //SEARCH
    45.         for(;;)
    46.         {
    47.             if (best.current == targetNode && best != null || open.Count == 0)
    48.             {
    49.                 Path foundPath = new Path();
    50.                 foundPath.gridNodes = new List<GridNode>();
    51.                 Expansion iterator = best;
    52.                 while(iterator != null)
    53.                 {
    54.                     foundPath.gridNodes.Add(iterator.current);
    55.                     iterator = iterator.previous;
    56.                 }
    57.                
    58.                 foundPath.gridNodes.Reverse();
    59.                 return foundPath;
    60.             }
    61.  
    62.             //FIND BEST SCORE
    63.             best = null;
    64.             foreach(Expansion expansion in open)
    65.             {
    66.                 if (best == null || expansion.toltalCost < best.toltalCost)
    67.                     best = expansion;
    68.             }
    69.  
    70.             ExpandPath();
    71.         }
    72.     }
    73.  
    74.     private void ExpandPath()
    75.     {
    76.         closed.Add(best.current);
    77.         open.Remove(best);
    78.         if (GridGraph.instance.gridType == GridGraph.GridType.square)
    79.         {
    80.             GridNode expansionNode = best.current;
    81.             expansionNode.gridNodeIndex.y -= 1;
    82.             if (PathNodeInBounds(expansionNode))
    83.                 AddToExpansionPath(GridGraph.instance.gridNodes[expansionNode.layer][(int)expansionNode.gridNodeIndex.x, (int)expansionNode.gridNodeIndex.y]);
    84.  
    85.             expansionNode = best.current;
    86.             expansionNode.gridNodeIndex.y += 1;
    87.             if (PathNodeInBounds(expansionNode))
    88.                 AddToExpansionPath(GridGraph.instance.gridNodes[expansionNode.layer][(int)expansionNode.gridNodeIndex.x, (int)expansionNode.gridNodeIndex.y]);
    89.  
    90.             expansionNode = best.current;
    91.             expansionNode.gridNodeIndex.x -= 1;
    92.             if (PathNodeInBounds(expansionNode))
    93.                 AddToExpansionPath(GridGraph.instance.gridNodes[expansionNode.layer][(int)expansionNode.gridNodeIndex.x, (int)expansionNode.gridNodeIndex.y]);
    94.  
    95.             expansionNode = best.current;
    96.             expansionNode.gridNodeIndex.x += 1;
    97.             if (PathNodeInBounds(expansionNode))
    98.                 AddToExpansionPath(GridGraph.instance.gridNodes[expansionNode.layer][(int)expansionNode.gridNodeIndex.x, (int)expansionNode.gridNodeIndex.y]);
    99.  
    100.             expansionNode = best.current;
    101.             for (int i = 0; i < expansionNode.gridNodesNeighbors.Length; ++i)
    102.                 AddToExpansionPath(expansionNode.gridNodesNeighbors[i]);
    103.         }
    104.         else if (GridGraph.instance.gridType == GridGraph.GridType.hex)
    105.         {
    106.             GridNode expansionNode = best.current;
    107.             expansionNode.gridNodeIndex.x -= 1;
    108.             if (PathNodeInBounds(expansionNode))
    109.                 AddToExpansionPath(GridGraph.instance.gridNodes[expansionNode.layer][(int)expansionNode.gridNodeIndex.x, (int)expansionNode.gridNodeIndex.y]);
    110.  
    111.             expansionNode = best.current;
    112.             expansionNode.gridNodeIndex.x += 1;
    113.             if (PathNodeInBounds(expansionNode))
    114.                 AddToExpansionPath(GridGraph.instance.gridNodes[expansionNode.layer][(int)expansionNode.gridNodeIndex.x, (int)expansionNode.gridNodeIndex.y]);
    115.  
    116.             expansionNode = best.current;
    117.             expansionNode.gridNodeIndex.x += 1;
    118.             expansionNode.gridNodeIndex.y -= 1;
    119.             if (expansionNode.gridNodeIndex.y % 2 != 0)
    120.                 expansionNode.gridNodeIndex.x -= 1;
    121.             if (PathNodeInBounds(expansionNode))
    122.                 AddToExpansionPath(GridGraph.instance.gridNodes[expansionNode.layer][(int)expansionNode.gridNodeIndex.x, (int)expansionNode.gridNodeIndex.y]);
    123.  
    124.             expansionNode = best.current;
    125.             expansionNode.gridNodeIndex.x -= 1;
    126.             expansionNode.gridNodeIndex.y -= 1;
    127.             if (expansionNode.gridNodeIndex.y % 2 == 0)
    128.                 expansionNode.gridNodeIndex.x += 1;
    129.             if (PathNodeInBounds(expansionNode))
    130.                 AddToExpansionPath(GridGraph.instance.gridNodes[expansionNode.layer][(int)expansionNode.gridNodeIndex.x, (int)expansionNode.gridNodeIndex.y]);
    131.  
    132.             expansionNode = best.current;
    133.             expansionNode.gridNodeIndex.x -= 1;
    134.             expansionNode.gridNodeIndex.y += 1;
    135.             if (expansionNode.gridNodeIndex.y % 2 == 0)
    136.                 expansionNode.gridNodeIndex.x += 1;
    137.             if (PathNodeInBounds(expansionNode))
    138.                 AddToExpansionPath(GridGraph.instance.gridNodes[expansionNode.layer][(int)expansionNode.gridNodeIndex.x, (int)expansionNode.gridNodeIndex.y]);
    139.  
    140.             expansionNode = best.current;
    141.             expansionNode.gridNodeIndex.x += 1;
    142.             expansionNode.gridNodeIndex.y += 1;
    143.             if (expansionNode.gridNodeIndex.y % 2 != 0)
    144.                 expansionNode.gridNodeIndex.x -= 1;
    145.             if (PathNodeInBounds(expansionNode))
    146.                 AddToExpansionPath(GridGraph.instance.gridNodes[expansionNode.layer][(int)expansionNode.gridNodeIndex.x, (int)expansionNode.gridNodeIndex.y]);
    147.  
    148.             expansionNode = best.current;
    149.             for (int i = 0; i < expansionNode.gridNodesNeighbors.Length; ++i)
    150.                 AddToExpansionPath(expansionNode.gridNodesNeighbors[i]);
    151.         }
    152.     }
    153.  
    154.     public void AddToExpansionPath(GridNode gridNode)
    155.     {
    156.         if (!visited[gridNode.layer][(int)gridNode.gridNodeIndex.x, (int)gridNode.gridNodeIndex.y] && gridNode.isTraversable)
    157.         {
    158.             visited[gridNode.layer][(int)gridNode.gridNodeIndex.x, (int)gridNode.gridNodeIndex.y] = true;
    159.             costToGoal = Vector2.Distance(gridNode.gridNodeIndex, targetNode.gridNodeIndex);
    160.             costToNextNode = Vector2.Distance(gridNode.gridNodeIndex, gridNode.gridNodeIndex);
    161.             costFromStart = best.costFromStart;
    162.  
    163.             open.Add(new Expansion(gridNode, best, costFromStart + costToNextNode + gridNode.cost, costToGoal));
    164.         }
    165.     }
    166.  
    167.     public void GenerateMovementGrid(Vector3 startingPosition, int floodFillDistance)
    168.     {
    169.         DegenerateGrid();
    170.         floodFillType = FloodFillType.walk;
    171.         startingNode = FindClosestGridNode(startingPosition);
    172.         this.floodFillDistance = floodFillDistance;
    173.         GridGraph.instance.gridNodes[startingNode.layer][(int)startingNode.gridNodeIndex.x, (int)startingNode.gridNodeIndex.y].render = true;
    174.         GridGraph.instance.gridNodes[startingNode.layer][(int)startingNode.gridNodeIndex.x, (int)startingNode.gridNodeIndex.y].tileType = GridNode.TileType.walk;
    175.         GenerateGrid();
    176.     }
    177.  
    178.     public void GenerateAttackGrid(Vector3 startingPosition, int floodFillDistance)
    179.     {
    180.         DegenerateGrid();
    181.         floodFillType = FloodFillType.attack;
    182.         startingNode = FindClosestGridNode(startingPosition);
    183.         this.floodFillDistance = floodFillDistance;
    184.         GenerateGrid();
    185.     }
    186.  
    187.     public void DegenerateGrid()
    188.     {
    189.         for (int k = 0; k < GridGraph.instance.layers.Count; ++k)
    190.             for (int i = 0; i < GridGraph.instance.width; ++i)
    191.                 for (int j = 0; j < GridGraph.instance.length; ++j)
    192.                 {
    193.                     GridGraph.instance.gridNodes[k][i, j].render = false;
    194.                     GridGraph.instance.gridNodes[k][i, j].tileType = GridNode.TileType.none;
    195.                 }
    196.     }
    197.  
    198.     private void GenerateGrid()
    199.     {  
    200.         floodFillCurrentDistance = 0;      
    201.         open = new List<Expansion>();
    202.         closed = new HashSet<GridNode>();
    203.         best = new Expansion(startingNode, 0);
    204.         best.current = startingNode;
    205.         open.Add(best);
    206.      
    207.  
    208.         visited = new List<bool[,]>();
    209.         for (int i = 0; i < GridGraph.instance.layers.Count; ++i)
    210.             visited.Add(new bool[GridGraph.instance.width, GridGraph.instance.length]);
    211.  
    212.         while (true)
    213.         {
    214.             if (open.Count > 0)
    215.                 ExpandFloodFill(open[0]);
    216.             else
    217.                 break;
    218.         }
    219.     }
    220.  
    221.     private void ExpandFloodFill(Expansion current)
    222.     {
    223.         open.Remove(current);
    224.         closed.Add(current.current);
    225.         floodFillCurrentDistance = current.currentFloodFillDistance + 1;
    226.         visited[current.current.layer][(int)current.current.gridNodeIndex.x, (int)current.current.gridNodeIndex.y] = true;
    227.  
    228.         if (GridGraph.instance.gridType == GridGraph.GridType.square)
    229.         {
    230.             GridNode expansionNode = current.current;
    231.             expansionNode.gridNodeIndex.y -= 1;
    232.             if (PathNodeInBounds(expansionNode))
    233.                 AddToExpansionFloodFill(GridGraph.instance.gridNodes[expansionNode.layer][(int)expansionNode.gridNodeIndex.x, (int)expansionNode.gridNodeIndex.y], floodFillCurrentDistance);
    234.  
    235.             expansionNode = current.current;
    236.             expansionNode.gridNodeIndex.y += 1;
    237.             if (PathNodeInBounds(expansionNode))
    238.                 AddToExpansionFloodFill(GridGraph.instance.gridNodes[expansionNode.layer][(int)expansionNode.gridNodeIndex.x, (int)expansionNode.gridNodeIndex.y], floodFillCurrentDistance);
    239.  
    240.             expansionNode = current.current;
    241.             expansionNode.gridNodeIndex.x -= 1;
    242.             if (PathNodeInBounds(expansionNode))
    243.                 AddToExpansionFloodFill(GridGraph.instance.gridNodes[expansionNode.layer][(int)expansionNode.gridNodeIndex.x, (int)expansionNode.gridNodeIndex.y], floodFillCurrentDistance);
    244.  
    245.             expansionNode = current.current;
    246.             expansionNode.gridNodeIndex.x += 1;
    247.             if (PathNodeInBounds(expansionNode))
    248.                 AddToExpansionFloodFill(GridGraph.instance.gridNodes[expansionNode.layer][(int)expansionNode.gridNodeIndex.x, (int)expansionNode.gridNodeIndex.y], floodFillCurrentDistance);
    249.  
    250.             for (int i = 0; i < expansionNode.gridNodesNeighbors.Length; ++i)
    251.                 AddToExpansionFloodFill(expansionNode.gridNodesNeighbors[i],floodFillCurrentDistance);
    252.         }
    253.     }
    254.  
    255.     private void AddToExpansionFloodFill(GridNode gridNode, int distance)
    256.     {
    257.         if (!visited[gridNode.layer][(int)gridNode.gridNodeIndex.x, (int)gridNode.gridNodeIndex.y] && distance < floodFillDistance + 1)
    258.         {
    259.             visited[gridNode.layer][(int)gridNode.gridNodeIndex.x, (int)gridNode.gridNodeIndex.y] = true;
    260.             if (gridNode.isTraversable)
    261.             {
    262.                 open.Add(new Expansion(gridNode, distance));
    263.                 GridGraph.instance.gridNodes[gridNode.layer][(int)gridNode.gridNodeIndex.x, (int)gridNode.gridNodeIndex.y].render = true;
    264.  
    265.                 if (floodFillType == FloodFillType.walk)
    266.                     GridGraph.instance.gridNodes[gridNode.layer][(int)gridNode.gridNodeIndex.x, (int)gridNode.gridNodeIndex.y].tileType = GridNode.TileType.walk;
    267.                 else if (floodFillType == FloodFillType.attack)
    268.                     GridGraph.instance.gridNodes[gridNode.layer][(int)gridNode.gridNodeIndex.x, (int)gridNode.gridNodeIndex.y].tileType = GridNode.TileType.attack;
    269.             }
    270.         }
    271.     }
    272.  
    273.     private bool PathNodeInBounds(GridNode gridNode)
    274.     {
    275.         return gridNode.gridNodeIndex.x >= 0 && gridNode.gridNodeIndex.y >= 0 && gridNode.gridNodeIndex.x < GridGraph.instance.width && gridNode.gridNodeIndex.y < GridGraph.instance.length;
    276.     }
    277.  
    278.     public GridNode FindClosestGridNode(Vector3 position)
    279.     {
    280.         GridNode closestGridNode = GridGraph.instance.gridNodes[0][0, 0];
    281.  
    282.         for (int k = 0; k < GridGraph.instance.layers.Count; ++k)
    283.         {
    284.             for (int i = 0; i < GridGraph.instance.width; ++i)
    285.             {
    286.                 for (int j = 0; j < GridGraph.instance.length; ++j)
    287.                 {
    288.                     float currentGridNodeDistance = Vector3.Distance(position, closestGridNode.position);
    289.                     float nextGridNodeDistance = Vector3.Distance(position, GridGraph.instance.gridNodes[k][i, j].position);
    290.  
    291.                     if (nextGridNodeDistance < currentGridNodeDistance)
    292.                         closestGridNode = GridGraph.instance.gridNodes[k][i, j];
    293.                 }
    294.             }
    295.         }
    296.         return closestGridNode;
    297.     }
    298.  
    299.     public class Expansion
    300.     {
    301.         public GridNode current;
    302.         public Expansion previous;
    303.         public float toltalCost;
    304.         public float costFromStart;
    305.         public float costToGoal;
    306.         public int currentFloodFillDistance;
    307.  
    308.         public Expansion(GridNode current,Expansion previous,float costFromStart,float costToGoal)
    309.         {
    310.             this.current = current;
    311.             this.previous = previous;  
    312.             this.costFromStart = costFromStart;
    313.             this.costToGoal = costToGoal;
    314.             this.toltalCost = costFromStart + costToGoal;
    315.         }
    316.  
    317.         public Expansion(GridNode current, int currentFloodFillDistance)
    318.         {
    319.             this.current = current;
    320.             this.currentFloodFillDistance = currentFloodFillDistance;
    321.         }
    322.     }
    323.    
    324.     void OnDrawGizmos()
    325.     {
    326.         if (path.gridNodes != null && drawGizmos)
    327.         {
    328.             try
    329.             {
    330.                 Gizmos.color = Color.green;
    331.  
    332.                 int startingNode = 0;
    333.                 for (int i = 1; i < path.gridNodes.Count; ++i)
    334.                 {
    335.                     int nextGridNode = i + 1;
    336.                     if (nextGridNode < path.gridNodes.Count)
    337.                     {
    338.                         float currentGridNodeDistance = Vector3.Distance(transform.position,path.gridNodes[startingNode].position);
    339.                         float nextGridNodeDistance = Vector3.Distance(transform.position,path.gridNodes[nextGridNode].position);
    340.  
    341.                         if (nextGridNodeDistance < currentGridNodeDistance)
    342.                             startingNode = i;
    343.                     }
    344.                 }
    345.  
    346.                 for (int i = startingNode; i < path.gridNodes.Count; ++i)
    347.                 {
    348.                     int nextGridNode = i + 1;
    349.                     if (nextGridNode < path.gridNodes.Count)
    350.                         Gizmos.DrawLine(path.gridNodes[i].position + new Vector3(0,0.01f,0),path.gridNodes[nextGridNode].position + new Vector3(0,0.01f,0));
    351.                 }
    352.             }
    353.             catch{}
    354.         }
    355.     }
    356. }
    357.  
    358.  
    Thanks
     
  2. BFGames

    BFGames

    Joined:
    Oct 2, 2012
    Posts:
    1,543
    A class is a reference type.
    A struct is a value type.

    http://www.albahari.com/valuevsreftypes.aspx

    So a struct works like ints, floats etc.

    A class is passed as a reference which means that particular class and not a copy of that class. So i guess you somewhere in your code set class instanceA = instanceB, so when you change a value in one you will also change it in the other class and mess up your system. You can create copy's of classes in these cases. You can look that up on google.
     
    Filtiarn_ and Kiwasi like this.
  3. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    As noted the key difference is reference versus value.

    With structs if you do

    structA = stuctB;

    You now have two copies of the struct. Changes to structA do not affect structB.

    With classes if you do

    classA = classB;

    You have a single class referenced in two places. Change classA and classB changes along with it.
     
    Filtiarn_ likes this.
  4. Filtiarn_

    Filtiarn_

    Joined:
    Jan 24, 2013
    Posts:
    173
    Thanks you two, I feel stupid and sorry for the stupid question.
     
  5. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Don't. Value versus reference is an odd concept to get your head around the first time you come across it.