Непонятное поведение при удалении объекта

Программирование на Юнити.

Непонятное поведение при удалении объекта

Сообщение accauntUnity3d 07 авг 2020, 22:29

Помогите пожалуйста разобраться, наткнулся на ошибку в своем коде, упростил его до следующего примера:

1) создаю префаб - простой спрайт и на нем класс Test содержащий только переменную int q и ее интерфейс Q

Синтаксис:
Используется csharp
using UnityEngine;
public class Test : MonoBehaviour {
    private int q;
    public int Q
    {
        get
        {
            return q;
        }
        set
        {
            q = value;
        }
    }
}
 


2)
Создаю кнопку, вешаю на нее скрипт который по клику делает следующее:
Синтаксис:
Используется csharp
    public void Test()
    {
        Transform testTransform = Resources.Load<Transform>("Test");//нахожу свой префаб
        if (GameObject.Find("QQ") != null)
        {
            Destroy(GameObject.Find("QQ"));//если объект уже был создан ранее - удаляю
        }
        Transform thisTest = Instantiate(testTransform);//вызываю заново объект
        Test test = thisTest.GetComponent<Test>();//получаю ссылку на скрипт с переменной
        thisTest.name = "QQ";//даю объекту имя что бы его можно было найти

        GameObject.Find("QQ").GetComponent<Test>().Q = 1;//ищу свой объект и задаю переменную
        Debug.Log(GameObject.Find("QQ").GetComponent<Test>().Q +=10);//добавляю к переменной 10 и вывожу
    }
 


В чем проблема:
1) после 1 го клика по кнопке: смотрю в инспекторе в режиме debug q = 1, Debug.Log выводит 11 - все в порядке
2) после 2го клика по той же кнопке: смотрю в инспекторе в режиме debug q = 0 (а должно быть снова q = 1), Debug.Log выводит снова 11
3) все последующие клики аналогично 2му

Вопрос:
- почему во 2й раз и далее q != 1 !?
- почему при этом Debug.Log выводит 11 !?
Такое ощущение, что GameObject.Find("QQ").GetComponent<Test>().Q как-то закешировался и ищет не тот объект который в сцене сейчас, а первый объект с таким-же именем удаленный между 1м и 2м кликом, и в нем записано что q=1. Может ли такое быть, или ошибка в другом?
accauntUnity3d
UNец
 
Сообщения: 12
Зарегистрирован: 12 июл 2020, 11:35

Re: Непонятное поведение при удалении объекта

Сообщение 1max1 07 авг 2020, 22:41

Destroy срабатывает только в следующем кадре, а в текущем объект еще существует. Обращайся к нему через thisTest.GetComponent<Test>(), не надо его искать еще раз, оно найдет тебе текущий неудаленный.
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Непонятное поведение при удалении объекта

Сообщение accauntUnity3d 07 авг 2020, 22:53

1max1 писал(а):Destroy срабатывает только в следующем кадре, а в текущем объект еще существует. Обращайся к нему через thisTest.GetComponent<Test>(), не надо его искать еще раз, оно найдет тебе текущий неудаленный.

Не искать не получится, это же просто сокращенный пример, что бы не тащить сюда мешок не относящегося к вопросу кода. А так, у меня загружаются из xml разные объекты и потом их нужно по определенной логике между собой связывать, я записываю в XML в массивы ID связанных объектов и потом после загрузки сцены ищу их и связываю как мне нужно.
Но суть я понял, спасибо! Буду искать способ вызвать в следующем кадре.
Последний раз редактировалось accauntUnity3d 07 авг 2020, 22:58, всего редактировалось 1 раз.
accauntUnity3d
UNец
 
Сообщения: 12
Зарегистрирован: 12 июл 2020, 11:35

Re: Непонятное поведение при удалении объекта

Сообщение accauntUnity3d 07 авг 2020, 22:55

Еще как вариант попробую не удалять объекты с одинаковыми ID, а переназначать, думаю так точно получится.
accauntUnity3d
UNец
 
Сообщения: 12
Зарегистрирован: 12 июл 2020, 11:35

Re: Непонятное поведение при удалении объекта

Сообщение 1max1 07 авг 2020, 22:58

Можно использовать это https://docs.unity3d.com/ScriptReferenc ... diate.html, но я не уверен в том что это хорошая практика)
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Непонятное поведение при удалении объекта

Сообщение accauntUnity3d 07 авг 2020, 23:03

1max1 писал(а):Можно использовать это https://docs.unity3d.com/ScriptReferenc ... diate.html, но я не уверен в том что это хорошая практика)

На сколько я могу понять из английского описания, это сработает только в редакторе, но не в билде, если так, то не подходит, а жаль, было бы решение)
accauntUnity3d
UNец
 
Сообщения: 12
Зарегистрирован: 12 июл 2020, 11:35

Re: Непонятное поведение при удалении объекта

Сообщение 1max1 07 авг 2020, 23:24

Могу предложить костыль, вроде как метод Find ищет сверху иерархии до конца, так вот, если при создании нового объекта его закинуть наверх в иерархии, должно найти его первым.
Синтаксис:
Используется csharp
thisTest.SetAsFirstSibling();
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Непонятное поведение при удалении объекта

Сообщение accauntUnity3d 07 авг 2020, 23:35

1max1 писал(а):Могу предложить костыль, вроде как метод Find ищет сверху иерархии до конца, так вот, если при создании нового объекта его закинуть наверх в иерархии, должно найти его первым.
Синтаксис:
Используется csharp
thisTest.SetAsFirstSibling();

Спасибо) не, я уже придумал, 2 в целом рабочих варианта, костыли конечно, но, не злые:

1) работает нормально, если искать через родителя

Синтаксис:
Используется csharp
        foreach (Transform tr in compartmentsTransform)
        {
            tr.GetComponent<Test>().Q = 1;
        }
 


2) и если запускать поиск в следующем кадре после удаления как Вы и сказали:

Синтаксис:
Используется csharp
    int frame = 0;
    private void Update()
    {
        if (frame > 0)
        {
            frame++;
            if (frame > 3)
            {
                frame = 0;
                LateClick();
            }
        }
    }


Синтаксис:
Используется csharp
private void Click(){
Destroy(GameObject.Find("QQ"));
frame = 1;
}
accauntUnity3d
UNец
 
Сообщения: 12
Зарегистрирован: 12 июл 2020, 11:35

Re: Непонятное поведение при удалении объекта

Сообщение samana 08 авг 2020, 13:51

Я совсем не понял, почему такой сложный подход у вас выбран, ведь всё можно упростить
Синтаксис:
Используется csharp
// удаляем старый QQ если он существовал на сцене
GameObject oldQQ = GameObject.Find("QQ");
if (oldQQ != null) Destroy(oldQQ);

// создаём префаб "Test" и тут же получаем ссылку на его скрипт Test. Изменяем переменные полученного компонента.
Test thisTest = Instantiate(Resources.Load<GameObject>("Test")).GetComponent<Test>();
thisTest.name = "QQ";
thisTest.Q = 1 + 10;
Debug.Log(thisTest.Q);
Аватара пользователя
samana
Адепт
 
Сообщения: 4738
Зарегистрирован: 21 фев 2015, 13:00
Откуда: Днепропетровск


Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 7