Search code examples
c#unity-game-enginemultidimensional-arraygameobject

SetActive reacts differently


Depending on an Input String I want to activate my GameObjects in the Script. My GameObjects own a public String I compare with the values of a given Array:

GameObject parent = GameObject.Find("Pick Ups");
int childCount = parent.transform.childCount;
foreach (var s in arr)
{
  for (int i = 0; i < childCount; ++i)
  {
    // Deactivate Target if it is not part of the Active Objects List
    if (s == parent.transform.GetChild(i).GetComponent<Rotator>().targetID)
    {
      parent.transform.GetChild(i).gameObject.SetActive(true);
      Debug.Log("Element " + s + " activated");
    } else { 
      parent.transform.GetChild(i).gameObject.SetActive(false);
    }
  }
}

This is working fine. Now I increase the amount of information I get for the input, store it in a 3-Dimensional Array and loop threw the first dimension that contains the same information as before:

var tArr = aTLString.Split('~')
                    .Select(x => x.Split('^')
                                  .ToArray()
                                  .Select(y => y.Split('`'))
                                                .ToArray())
                                  .ToArray();

for (int j = 0; j < tArr.GetLength(0); ++j)
{
  for (int i = 0; i < childCount; ++i)
  {
    // Deactivate Target if it is not part of the Active Objects List
    if (tArr[j][0][0] == parent.transform.GetChild(i).GetComponent<Rotator>().targetID)
    {
      parent.transform.GetChild(i).gameObject.SetActive(true);
      Debug.Log("Element " + tArr[j][0][0] + " activated");
    } else { 
      parent.transform.GetChild(i).gameObject.SetActive(false);
    }
  }
}

This time, the element is not activated. I get the Console Feedback, that the Element is activated (So tArr[j][0][0] contains the correct String) but the SetActivate seems not to be working.

I don't understand the issue


Solution

  • In each iteration over tArr, you are calling SetActive on all the objects.
    Even if an object is matched in the first pass, it is deactivated in subsequent passes, making only the lass pass effective.

    Your algorithm is tantamount to (tried to make it as concise as possible):

    public class Thing
    {
        public int Id;
        public bool Active = false;
        public Thing(int id) { Id = id; }
    }
    
    void Main()
    {
        var targetIds = new int[] {2, 5, 7 };
        var things = new Thing[] {new Thing(1), new Thing(2), new Thing(3)};
    
        foreach (var id in targetIds)
        {
            foreach (var thing in things)
            {
                thing.Active = thing.Id == id;
                Console.WriteLine($"{thing.Id} active: {thing.Active}");
            }
        }
    }
    

    This outputs:

    1 active: False
    2 active: True
    3 active: False
    1 active: False
    2 active: False
    3 active: False
    1 active: False
    2 active: False
    3 active: False
    

    You can see that even though ID 2 was matched in the first iteration over targetIds, it is then reset in subsequent passes.

    What you probably want to do is first set all the objects to be inactive, and only then iterate over tArr and activate matched objects, but don't deactivate unmatched ones.

    Alternatively you could iterate just once over the objects and activate them if their id is contained in tArr.

    foreach (var thing in things)
    {
        thing.Active = targetIds.Contains(thing.Id);
    }