Не корректная робота transform.childCount
Емм... Я если честно вообще в изумлении и ни черта не понимаю. У меня есть gameObject "Content", к которому прикреплён GridLayoutGroup и ContentSizeFilter. Этот "Content" хранит в себе список дочерних элементов с которыми будет взаимодействовать игрок. И получается то что динамически будет меняться размер(имеется ввиду transform.childCount) этого Content. Мне нужно программно отслежывать эти изменения дабы делать другие действия.
public class ObserverChildCount : MonoBehaviour
{
[SerializeField] private Host host;
private int lastCount;
private bool isLoad;
private void Update()
{
if (lastCount != transform.childCount && isLoad)
{
Debug.Log($"Send. lastCount {lastCount} | childCount {transform.childCount}");
//HandlerSendItemInBase.Instance.SetHostForSend(host);
lastCount = transform.childCount;
}
}
public void SetIsLoad(bool state)
{
if (state)
{
Debug.Log($"{host} | lastCount - {lastCount} ||| childCount - {transform.childCount}");
lastCount = transform.childCount;
}
isLoad = state;
}
}
Этим как раз и занимается этот скрипт. Update проверяет были изменения. isLoad - флаг что бы начать наблюдение за изменением количества. Если флаг false то идёт изначальное заполнение "Content" по этому условие в Update не срабатывает. Когда прошёл Instantiate всех дочерних элементов флаг переходит в значение true и lastCount приравнивается к текущему значению. По сути прошла настройка всего для корректной роботы условия в Update. Но случается следущее.
Player | lastCount - 1 ||| childCount - 2
Это данные приходят с SetIsLoad. Соответственно следующая строчка коду приравнивает lastCount к childCount. НО. Дальше
Send. lastCount 2 | childCount 1
Данные первого прохождения цикла после SetIsLoad. Сейчас дальше сложно, постараюсь описать максимально понятно. Прошу понять и помочь. gameObject "Content" активируется по нажатию кнопки. При активации у него проверяется childCount и если там есть что то то удаляется. Дабы данные были свежими. И isLoad как раз выполняет роль регулировщика(что нужно делать и когда). В SetIsLoad в нужный момент обновляет lastCount, но данные в него приходят не корректные. На самом деле там не 2 а 1. Дело в том что когда я активирую второй раз Content то все дочерние элементы удаляются но childCount не становится 0 а когда идёт вызов SetIsLoad(true) то к не обнулившемуся childCount добавляется count новых дочерних элементов. По этому в lastCount записывается 2 а не 1. Дальше хуже. После SetIsLoad едёт первый запуск Update. isLoad - true, что даёт уже право на срабатывание условия. lastCount у нас соответственно неверный а childCount уже обновился и стал 1(то есть правильным) и идёт ложное срабатывание. Я не могу понять, почему????
lastCount = transform.childCount;
В SetIsLoad срабатывает не правильно. На момент когда вызывается SetIsLoad(true) нету никаких действий по поводу дочерних элементов. Все данные уже загружены. Но childCount не обновляется.
Ответы (1 шт):
Я предполагаю, что дело в том, как вы удаляете текущие дочерние объекты. Тут есть две особенности, которые вместе или по отдельности могут давать описанный результат.
- Если вы используете обычный Destroy(), то он является отложенным, и не выполняется сразу же.
- Если вы удаляете дочерние объекты, использую цикл похожий на этот, то можете получить странное поведение, когда обрабатываться будет только каждый второй объект. Так реализуется IEnumerator в классе Transform(как и во многих других кстати).
foreach (Transform child in transform) { child.parent = null; }
Попробуйте удалять элементы следующим способом:
using System.Linq;
foreach (Transform child in observerChildCountInstance.transform.Cast<Transform>().ToArray())
{
Destroy(child.gameObject); // это вызовет отложенное удаление
child.SetParent(null); // а это удалит его из списка дочерних объектов прямо сейчас
}
Этот же цикл можно переписать используя DestroyImmediate, но это не так показательно. Так же на основе этих знаний, можно написать реализацию и без Linq, например перебирая элементы с конца, но это уже тема для другого вопроса.