Weird interaction on unity editor - C# 2d arrays

Okay, there is a bug in my game and i tried to narrow it down to the following codes:
The problem is when i change a value to an array A, it seems to also apply the change to another array B.

Can anyone tell me why this would happen please, or any idea what is going wrong, I have been trying so long to figure out whats happening, many thanks.

public class SomeClass : MonoBehaviour {

    public GameObject theSave;
    private Save saveAccess;

    void Start () {
        saveAccess= theSave.GetComponent<Save>();
        StartCoroutine(SaveGame_waitSec(1f));
    }

    private IEnumerator SaveGame_waitSec(float sec)
    {
        yield return new WaitForSeconds(sec);
        SaveGame();
    }


    void SaveGame() {

        saveAccess.undo[0, 0] = 0;
        saveAccess.curr[0, 0] = 0;

        Debug.Log("set undo[0,0] = 20 -- BEFORE: " + saveAccess.undo[0, 0]);   //output = 0
        saveAccess.undo[0, 0] = 20;
        Debug.Log("set undo[0,0] = 20 -- DONE: " + saveAccess.undo[0, 0]);   //output = 20

        Debug.Log("set curr[0,0] = 99 -- BEFORE: " + saveAccess.curr[0, 0]);   //output = 20
        saveAccess.curr[0, 0] = 99;
        Debug.Log("set undo[0,0] = 99 -- DONE: " + saveAccess.curr[0, 0]);   //output = 99

        Debug.Log("NOW, PRINT undo[0,0], it should be 20: " + saveAccess.undo[0, 0]);   //output = 99
        Debug.Log("NOW, PRINT curr[0,0], it should be 99: " + saveAccess.curr[0, 0]);   //output = 99

        }
}



public class Save: MonoBehaviour {

    public int[,] curr = new int[8, 7];
    public int[,] undo = new int[8, 7];

}

pls send help T_T

One thing that may be worth doing for debug sake is to turn those fields in Save into properties. And put a breakpoint on the set(). Then, see if the variable is indeed being modified for “undo” on the line were you set “curr”. What do you see then?

Also, take a look at your IDE “watch” window, and add these values there. See if they are set there too.

Okay, i’ve narrow the problem down even further.

The problem seems to be this line of code: (line 20)
saveloadToAccess.SetCurrUndoGameState(saveloadToAccess.GetCurrCurrGameState());
if i comment out this line of code, everything just works normally, i.e. it would not change the value of the other array.

Any idea why this happens? Also, you can copy and paste the code to try it out to see whether if you get the same results.

i also tried to duplicate this behaviour with two integers, like
int a, b = 0;
a = b;
a = 10;
and obviously the value of b is still 0
But this is exactly what happened in my code, but using two 2d array instead of two int …

one more thing is, the unity scene inspector wont serialise 2d arrays, so i can’t see the value through the inspector (which would make debugging way easier -,-)

ps: i’m sorry for my horribly named variables ><

//******* C# File Number 1 ********
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ParentPlayerObject : MonoBehaviour {
    public GameObject thesaveload;
    private SaveLoad saveloadToAccess;
    private bool yesno = false;

    void Start () {
        saveloadToAccess = thesaveload.GetComponent<SaveLoad>();
}

    void Update () {
        if (Input.GetMouseButton(0)&&yesno==false){
                yesno = true;

                saveloadToAccess.SetCurrUndoGameState(saveloadToAccess.GetCurrCurrGameState());

                Debug.Log("set UNDO[0,0] = 20 -- BEFORE: " + saveloadToAccess.GetCurrUndoGameState(0, 0)); //output=0
                saveloadToAccess.SetCurrUndoGameState(20, 0, 0);
                Debug.Log("set UNDO[0,0] = 20 -- DONE: " + saveloadToAccess.GetCurrUndoGameState(0, 0)); //output=20

                Debug.Log("set curr[0,0] = 99 -- BEFORE: " + saveloadToAccess.GetCurrCurrGameState(0, 0));   //output = 20
                saveloadToAccess.SetCurrCurrGameState(99, 0, 0);
                Debug.Log("set curr[0,0] = 99 -- DONE: " + saveloadToAccess.GetCurrCurrGameState(0, 0));   //output = 99

                Debug.Log("NOW, PRINT UNDO[0,0], IT SHOULD BE 20: " + saveloadToAccess.GetCurrUndoGameState(0, 0));   //output = 99
                Debug.Log("NOW, PRINT curr[0,0], IT SHOULD BE 99: " + saveloadToAccess.GetCurrCurrGameState(0, 0));   //output = 99
               }
        }
}

//******* End of C# File number 1 ******


//****** C# File number 2 *******

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System;

public class SaveLoad : MonoBehaviour
{
    private int[,] currerentCurrerentGameState = new int[8, 7];
    private int[,] currerentUndoGameState = new int[8, 7];


    public int GetCurrCurrGameState(int i, int j)
    {
        return currerentCurrerentGameState[i, j];
    }
    public int[,] GetCurrCurrGameState()
    {
        return currerentCurrerentGameState;
    }

    public void SetCurrCurrGameState(int num, int i, int j)
    {
        currerentCurrerentGameState[i, j] = num;
    }


    public int GetCurrUndoGameState(int i, int j)
    {
        return currerentUndoGameState[i, j];
    }
    public int[,] GetCurrUndoGameState()
    {
        return currerentUndoGameState;
    }

    public void SetCurrUndoGameState(int num, int i, int j)
    {
        currerentUndoGameState[i, j] = num;
    }
    public void SetCurrUndoGameState(int[,] array)
    {
        currerentUndoGameState = array;
    }
}
//******** end of C# file number 2 ********

[Solved]
Okay… I think i know found the problem, but i don’t know why this would happen…

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SomeObject : MonoBehaviour {

    int[] aa = new int[1];
    int[] bb = new int[1];

    void Start () {

        aa[0] = 0;
        bb[0] = 0;

        aa = bb;

        bb[0] = 10;

        Debug.Log("aa[0] is " + aa[0]);    // output is 10
    }

I mean, i could easily fix it now, simply use a loop to loop through the array instead of saying aa=bb, but can someone explain why i can’t say aa=bb, but instead i have to say aa[0]=bb[0]?

Many thanks and if you are also facing the same problem, please reply and share your problem/fix, thanks and have a nice day :slight_smile:

So arrays are reference types in C#. It’s why I use them less often than generics.

If you set an array equal to another array, you are setting it to the same position in memory. They are effectively the same variable.

        aa[0] = 0;
        bb[0] = 0;

        System.Array.Copy(bb, aa, bb.Length);

        bb[0] = 10;
        Debug.Log("aa[0] is " + aa[0]);    // output is 10

Use System.Array.Copy to copy the contents of one array to another, while instantiating it as a new object of the same value.

That, or use List(). I prefer the latter because of its mutability, since an array’s size cannot be altered after instantiation. But if arrays are best for you, that’s the way to do it.

1 Like

Thanks for the explanation, really helps a lot :slight_smile:
Yes, i should have used List() already. It just happens that i don’t need to resize the array, and i’m not very familiar with 2D List. But i would say for 1d array, List is defo a better choice.

1 Like

For a “2D list” that does not need to be updated, you could use a Dictionary. That is essentially a list of key value pairs. However, Dictionaries do not support some arbitrary ordering. A dictionary has basically no care in the world what order it’s data is stored or accessed in. While you can certainly manipulate order for data in a Dictionary, I find the following to be great for sorting and ordering “2 dimensional data” in generics:

List<KeyValuePair<int,int>> ListOfValues = new List<KeyValuePair<int,int>>();
//or just stick with arrays!
List<int[]> ListOfValues = new List<int[]>();

You can easily sort and order data both by the “Keys” and the “Values”. However, a major downside of this is that the KeyValuePairs are immutable/read only. If you want to change values, you will need to determine the index and do:

ListOfKeyValues.RemoveAt(x);
ListOfKeyValues.Insert(x, new KeyValuePair<int,int>(10,5));

Which makes it a bit of a hassles sometimes, and a little less readable. Dictionaries on the other hand can be updated just by finding the needed reference and setting the Key or Value directly.

1 Like