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. Dismiss Notice

setting variable on element from array not working

Discussion in 'Scripting' started by saint_george_23, Oct 24, 2020.

  1. saint_george_23

    saint_george_23

    Joined:
    Oct 22, 2015
    Posts:
    4
    Hi, I've been banging my head against this problem for over a day now, and I'm sure I'm missing something really straightforward, please help!

    I've tried to simplify the problem, so made the test script below which is called in start:

    Code (CSharp):
    1.  
    2.  
    3.     void Test(int q, int r, int elevation)
    4.     {
    5.         HexCoord h = GetHexAt(q, r);
    6.         h.elevation = elevation;
    7.         Debug.Log($"elevation {h.elevation}");  //this outputs 1
    8.         Debug.Log($"elevation {hexes[q,r].elevation}"); //this outputs 0
    9.         //hexes[q, r].elevation = elevation;
    10.  
    11.         UpdateHexVisuals();
    12.     }
    13.  
    14.     public HexCoord GetHexAt(int q, int r) {
    15.         return hexes[q, r];
    16.     }
    17.  
    I would expect both of my debug.log entries to be 1, but they aren't.

    The commented code below the debug.log works, and everything behaves correctly. I realise in this instance there isn't much benefit in factoring out this code, but it is useful in the bigger picture.

    I'd be grateful if someone could explain why assigning elevation via this method doesn't seem to be actually changing the elevation of the object in the hexes array.

    Full code below.


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5.  
    6. public class MapAxial : MonoBehaviour
    7. {
    8.     public GameObject HexPrefab;
    9.  
    10.     public Mesh meshWater;
    11.     public Mesh meshFlat;
    12.     public Mesh meshRaised;
    13.     public Mesh meshCliff;
    14.  
    15.     public Material MatDesert;
    16.     public Material MatRock;
    17.     public Material MatGrass;
    18.     public Material MatWater;
    19.     public Material MatCliff;
    20.  
    21.     public int mapHeight; //in hexes
    22.     public int mapWidth; //in hexes
    23.  
    24.     protected HexCoord[,] hexes;
    25.     protected Dictionary<HexCoord, GameObject> hexToGameObjectMap;
    26.  
    27.     void Start()
    28.     {
    29.         GenerateMap();
    30.  
    31.         Test(2,2,1);
    32.     }
    33.  
    34.     void Test(int q, int r, int elevation)
    35.     {
    36.         HexCoord h = GetHexAt(q, r);
    37.         h.elevation = elevation;
    38.         Debug.Log($"elevation {h.elevation}");  //this outputs 1
    39.         Debug.Log($"elevation {hexes[q,r].elevation}"); //this outputs 0
    40.         //hexes[q, r].elevation = elevation;
    41.  
    42.         UpdateHexVisuals();
    43.     }
    44.  
    45.     public HexCoord GetHexAt(int q, int r) {
    46.         return hexes[q, r];
    47.     }
    48.  
    49.     virtual public void GenerateMap() {
    50.  
    51.         hexes = new HexCoord[mapWidth, mapHeight]; //create array to store hexCoord structs
    52.         hexToGameObjectMap = new Dictionary<HexCoord, GameObject>(); //create dictionary
    53.  
    54.  
    55.         //Generate a flat map
    56.  
    57.         for (int column = 0; column < mapWidth; column++)
    58.         {
    59.             for (int row = 0; row < mapHeight; row++)
    60.             {
    61.                 //add new HexCoord to array
    62.                 HexCoord h = new HexCoord(column, row);
    63.                 hexes[column, row] = h;
    64.  
    65.                 //instantiate hex GameObject and position it using method in HexCoord
    66.                 GameObject hex_go = (GameObject)Instantiate(HexPrefab, h.WorldPosition(), Quaternion.identity, this.transform);
    67.  
    68.                 //name the new hex GameObject in the hierarchy
    69.                 hex_go.name = "hex_" + column + "_" + row;
    70.  
    71.                 //map the game object to the data structure in the dictionary
    72.                 hexToGameObjectMap[h] = hex_go;
    73.  
    74.                 StaticBatchingUtility.Combine(this.gameObject);
    75.             }
    76.         }
    77.         UpdateHexVisuals();
    78.     }
    79.  
    80.     public void UpdateHexVisuals()
    81.     {
    82.         for (int column = 0; column < mapWidth; column++)
    83.         {
    84.             for (int row = 0; row < mapHeight; row++)
    85.             {
    86.                 HexCoord h = hexes[column, row];
    87.                 GameObject hex_go = hexToGameObjectMap[h];
    88.  
    89.                //get meshrenderer of hex gameObject and assign it default desert material
    90.                 MeshRenderer mr = hex_go.GetComponentInChildren<MeshRenderer>();
    91.                 mr.material = MatDesert;
    92.                 if (h.elevation > 0)
    93.                 {
    94.                     Debug.Log($" Q {h.Q} R{h.R}");
    95.                     mr.material = MatGrass;
    96.                 }
    97.  
    98.                 //get meshfilter of hex gameobject and assign it flat mesh as a default
    99.                 MeshFilter mf = hex_go.GetComponentInChildren<MeshFilter>();  
    100.                 mf.mesh = meshFlat;
    101.             }
    102.         }
    103.     }  
    104.  


    HexCoord, adapted from this code on GitHub (https://github.com/akhra/HexCoord)
    Code (CSharp):
    1. public struct HexCoord
    2. {
    3.  
    4.     /// <summary>
    5.     /// Position on the q axis.
    6.     /// </summary>
    7.     [SerializeField]
    8.     public int Q;
    9.     /// <summary>
    10.     /// Position on the r axis.
    11.     /// </summary>
    12.     [SerializeField]
    13.     public int R;
    14.  
    15.  
    16.     public float elevation;
    17.  
    18.     /// <summary>
    19.     /// Initializes a new instance of the <see cref="Settworks.Hexagons.HexCoord"/> struct.
    20.     /// </summary>
    21.     /// <param name="q">Position on the q axis.</param>
    22.     /// <param name="r">Position on the r axis.</param>
    23.     public HexCoord(int q, int r)
    24.     {
    25.         this.Q = q;
    26.         this.R = r;
    27.         this.elevation=0;
    28.         Debug.Log("this code called");
    29.     }
    30.  
    31.     /// <summary>
    32.     /// Position on the cubic z axis.
    33.     /// </summary>
    34.     /// <remarks>
    35.     /// The q,r coordinate system is derived from an x,y,z cubic system with the constraint that x + y + z = 0.
    36.     /// Where x = q and y = r, this property derives z as <c>-q-r</c>.
    37.     /// </remarks>
    38.     public int S
    39.     {
    40.         get { return -Q - R; }
    41.     }
    42.  
    43.     /// <summary>
    44.     /// Offset x coordinate.
    45.     /// </summary>
    46.     /// <remarks>
    47.     /// Offset coordinates are a common alternative for hexagons, allowing pseudo-square grid operations.
    48.     /// Where y = r, this property represents the x coordinate as <c>q + r/2</c>.
    49.     /// </remarks>
    50.     public int O
    51.     {
    52.         get { return Q + (R >> 1); }
    53.     }
    54.  
    55.     /// <summary>
    56.     /// Unity position of this hex.
    57.     /// </summary>
    58.     public Vector2 Position()
    59.     {
    60.         return Q * Q_XY + R * R_XY;
    61.     }
    62.  
    63.     public Vector3 WorldPosition() {
    64.  
    65.         float x = Position().x;
    66.         float y = 0; //could change to elevation??
    67.         float z = Position().y;
    68.  
    69.         return new Vector3(x, y, z);
    70.     }
    71.  
    72.     static readonly Vector2 Q_XY = new Vector2(SQRT3, 0);
    73.     static readonly Vector2 R_XY = new Vector2(SQRT3 / 2, 1.5f);
    74.     static readonly Vector2 X_QR = new Vector2(SQRT3 / 3, 0);
    75.     static readonly Vector2 Y_QR = new Vector2(-1 / 3f, 2 / 3f);
    76. }
     
  2. Stevens-R-Miller

    Stevens-R-Miller

    Joined:
    Oct 20, 2017
    Posts:
    664
    The reason your outputs are different is that HexCoord is a struct, not a class. When you assign one class to another, all you are doing is assigning a reference to that class (some people say "pointer" instead of "reference"). So, in this code, the output is the same at Line 14 as it is at Line 13, and it is the same at Line 19 as it is at Line 18, because
    box2
    and
    box1
    contain references to the same object of class
    DataBox
    :

    Code (CSharp):
    1. public class Demo
    2. {
    3.     public void Start()
    4.     {
    5.         DataBox box1 = new DataBox();
    6.  
    7.         box1.x = 3;
    8.  
    9.         DataBox box2;
    10.  
    11.         box2 = box1;
    12.  
    13.         print(box1.x);
    14.         print(box2.x);
    15.  
    16.         box1.x = 4;
    17.  
    18.         print(box1.x);
    19.         print(box2.x);
    20.     }
    21. }
    22.  
    23. public class DataBox
    24. {
    25.     public int x;
    26. }
    This outputs the following:

    3
    3
    4
    4


    But, if you make DataBox a struct, assigning it to another struct copies the values in it, not just a reference to it. After that assignment, you have two different copies of the struct, so changing one does not change the other.

    public struct DataBox
    {
    public int x;
    }


    The above gets you this output:

    3
    3
    4
    3


    This is all because classes are reference types, and structs are value types. There is a lot of information on the internet about this. I advise you to limit your reading to reliable sources (stuff written by Microsoft, for example), as this is one of the most misunderstood, yet fundamental, concepts you need to know when programming in C#.

    Good luck!
     
    Last edited: Oct 24, 2020
    seejayjames likes this.
  3. saint_george_23

    saint_george_23

    Joined:
    Oct 22, 2015
    Posts:
    4
    Thanks very much, that's a super clear explanation. I'll go away and do some reading.
     
    Stevens-R-Miller likes this.