Search code examples
c#unity-game-engineuser-interface

Why doesn't the first instantiated object follow directions?


I'm building a fitness tracking app. The idea behind this specific part of the UI is that the user can add sets to the drills they are doing by pressing the "+Set" button. It instantiates a new prefab in a scrollview. When instantiated, the label should update with a set number ("Set 1," "Set 2", etc.).

UI example

As you can see, though, the set labels aren't working correctly. The first label never updates with the correct number. And even though the int for the set is increased at the end of the instantiation instructions (so after the first one is instantiated, the number reads as "2"), the next set will update the label to read as 1 less than the actual int.

Here's what's being shown in the script when I'm testing:

enter image description here

This is driving me nuts, as I can't figure out for the life of me why it won't behave.

Here's the code that gets called when the button is pushed.

public class ActiveWorkoutDrillObject : MonoBehaviour

public TMP_Text drilNameDisplay;
public List<GameObject> sets = new List<GameObject>();
public GameObject scrollViewArea;
public Transform setsScrollview;
public GameObject setObject;
public int totalReps;
public int setNum;
public GameObject helpScreen;

void Start()
{
    setNum = 0;
}

public void AddSet()
{
    setNum++;
    
    GameObject _set = setObject;

    Instantiate(_set, setsScrollview);
    sets.Add(_set);

    int _viewSize = sets.Count * 155;
    scrollViewArea.GetComponent<RectTransform>().sizeDelta = new Vector2(950, _viewSize);
    
    _set.GetComponent<ActiveWorkoutSetObject>().UpdateSetText(setNum);
}

Here's the code for the instantiated object that should be updating the text.

public class ActiveWorkoutSetObject : MonoBehaviour

private ActiveWorkoutDrillObject activeWO;
public int reps;
public TMP_Text setsDisplay;
public TMP_Text repsDisplay;

void Start()
{
    activeWO = GameObject.FindObjectOfType<ActiveWorkoutDrillObject>();
}

public void UpdateSetText(int _setNum)
{
    setsDisplay.text = _setNum.ToString();
}

As best I can tell when I've added debug lines, all of the instructions are being called, the correct information is being sent to the methods, and it should be updating with the correct text...but it just won't.


Solution

  • You assign your _set variable as the prefab (setObject), and then do your modifications on that, so you're only ever changing the label of the prefab. This has the effect of delaying the label change, since you clone the prefab with Instantiate before changing its value:

    1. AddSet is ran:
      1. Create clone from prefab (clone gets default label)
      2. prefab.UpdateSetText(1) is ran, giving the prefab (but not the clone) "label #1"
    2. AddSet is ran again:
      1. Create clone from prefab (clone gets "label #1")
      2. prefab.UpdateSetText(2) is ran, giving the prefab (but not the clone) "label #2"
    3. ...repeated

    You need to instead assign _set to the newly created object (the return value of Instantiate) so the cloned object gets modified, not the prefab:

    GameObject _set = setObject;
    
    Instantiate(_set, setsScrollview);
    sets.Add(_set);
    ...
    

    should be

    GameObject _set = Instantiate(setObject, setsScrollview);
    sets.Add(_set);
    ...