NullReferenceException, при этом работает...

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

NullReferenceException, при этом работает...

Сообщение Kakaha_228 30 апр 2023, 22:34

Решил после большого (почти год) переыва вернуться к разработке одного старого симулятора автомобиля, но на сей раз решил перенести на андроид. В итоге переноса сломал почти всё в проекта и большую часть пришлось переделывать. Но вот я никак не пойму логику ошибки в этом коде:
Синтаксис:
Используется csharp
public class Interaction : MonoBehaviour
{
        public Image indicator;
        public Text messageText;
        RaycastHit hit;

        public KeyCode control = KeyCode.E;
        public float RayDist = 1.0f;

        void Update()
        {
                if (Physics.Raycast(transform.position, transform.forward, out hit, RayDist))
                {
                        if (hit.collider.tag == "Item")
                        {
                                indicator.enabled = true;
                messageText.text = hit.collider.GetComponent<Item>().messageText;
                if (Input.GetKeyDown(control))
                                {
                                        hit.collider.GetComponent<Item>().Interaction();
                                }
                        }
                        else
                        {
                                indicator.enabled = false;
                                messageText.text = "";
                        }
                }
        }

        private void OnDrawGizmos()
        {
                Gizmos.color = Color.white;
                Gizmos.DrawRay(transform.position, transform.forward * RayDist);
        }

        public void Use()
        {
                hit.collider.GetComponent<Item>().Interaction();
    }
}

Дабы сильно не морочить голову с интеративом, я решил просто продублировать вызов, выполянемый при интерактиве. Это работает, но при каждом нажатии UI кнопки действия в консоли я вижу сообщение:
NullReferenceException: Object reference not set to an instance of an object
Interaction.Use () (at Assets/Scripts/Interaction/Interaction.cs:44)
Строка 44 это как раз строка "hit.collider.GetComponent<Item>().Interaction();". Опять же скажу, что код работает более чем прекрасно, но консоль не даёт покоя.
Я как вариант пробовал вместо:
Синтаксис:
Используется csharp
public void Use()
        {
                hit.collider.GetComponent<Item>().Interaction();
    }
 
...такой вариант:
Синтаксис:
Используется csharp
public void Use()
        {
                if (hit.collider.tag == "Item")
                {
                        hit.collider.GetComponent<Item>().Interaction();
                }
    }
 
В таком случае ошибка уходила, но появлялась новая проблема: эффект памяти. При помощи данного интерактива я открываю и закрываю двери/ворота, сажусь в машину, завожу её, включаю светотехнику и прочее. Но с данным эффектом памяти я могу не сесть в машину, т.к. оно запомнит, что последний объект был выходом из машины и при любой попытке сесть я тут же выхожу обратно. Так же могу включить свет в гараже и вместе с этим машина заглохнет или включится какой-нибудь поворотник. А ещё у меня покраска реализована через этот же интерактив и часто бывало, что при закрывании двери машины она меняла цвет и в итоге после хлопка краснела. И при всём этом это лишь дублёр действия с клавиши на клавиатуре, а при нажатии на клавиши это же действие выполняется без каких-либо проблем и эффектов памяти...
В целом это не столь критично, столько любопытно понять, почему же происходит этот эфффект памяти или как ещё можно убрать эту ошибку...
Аватара пользователя
Kakaha_228
UNIт
 
Сообщения: 60
Зарегистрирован: 21 фев 2021, 14:12

Re: NullReferenceException, при этом работает...

Сообщение Alkos26Rus 30 апр 2023, 23:20

ты не RaycastHit hit; выноси в отдельное поле, а сам объект с которым уже столкнулся рейкаст и при нажатии кнопки проверяй существует ли этот объект
Аватара пользователя
Alkos26Rus
Адепт
 
Сообщения: 1640
Зарегистрирован: 26 ноя 2020, 17:52
Откуда: Москва

Re: NullReferenceException, при этом работает...

Сообщение 1max1 30 апр 2023, 23:27

Какой смысл в Use() если ты и так вызываешь интерактив в Input.GetKeyDown(control)
Или это гибрид логики для пк и для мобилы в одном флаконе?
Ты можешь попытаться сделать hit нулейбл типом дабы избегать запоминания.

Синтаксис:
Используется csharp
public class Interaction : MonoBehaviour
{
    public Image indicator;
    public Text messageText;
    RaycastHit? _hit;

    public KeyCode control = KeyCode.E;
    public float RayDist = 1.0f;

    void Update()
    {
        _hit = null;

        if (Physics.Raycast(transform.position, transform.forward, out var hit, RayDist))
        {
            if (hit.collider.tag == "Item")
            {
                _hit = hit;

                indicator.enabled = true;
                messageText.text = hit.collider.GetComponent<Item>().messageText;
                if (Input.GetKeyDown(control))
                {
                    hit.collider.GetComponent<Item>().Interaction();
                }
            }
            else
            {
                indicator.enabled = false;
                messageText.text = "";
            }
        }
    }

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.white;
        Gizmos.DrawRay(transform.position, transform.forward * RayDist);
    }

    public void Use()
    {
        if (_hit != null)
            _hit.Value.collider.GetComponent<Item>().Interaction();
    }
}


А NullReferenceException иногда бывает если чушь засунул в кнопку через код, при чем метод не отображается в инспекторе, еще при дублировании скриптов на объекте, тут надо с дебаг логом искать.
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: NullReferenceException, при этом работает...

Сообщение Kakaha_228 01 май 2023, 21:50

1max1 писал(а):Или это гибрид логики для пк и для мобилы в одном флаконе?

Можно и так сказать. Я решил не отказываться от управления с клавиатуры, т.к. это полезно для отладки и оказался прав...
1max1 писал(а):Ты можешь попытаться сделать hit нулейбл типом дабы избегать запоминания.

Интересный варинт. Но вот только теперь этот баг приобрёл другой вид памяти:




Теперь если отвести камеру от интерактивного предмета, то индиктор остаётся активным и в тексте отображается название предмета/действия. При наведении курсора на другой интерактивный предмет вместо предыдущего отображается информация о новом, но он остаётся в памяти скрипта... Ещё при нажатии кнопки действия во время этого бага взаимодействия с ним не происходит. Выходит, что он как-бы запоминается и при этом как-бы нет :-?
Да не нужна мне подпись...
Аватара пользователя
Kakaha_228
UNIт
 
Сообщения: 60
Зарегистрирован: 21 фев 2021, 14:12

Re: NullReferenceException, при этом работает...

Сообщение 1max1 01 май 2023, 23:16

Ты точно не вчера начал юнити изучать?

Синтаксис:
Используется csharp
    void Update()
    {
        _hit = null;
        indicator.enabled = false;
        messageText.text = "";
...
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: NullReferenceException, при этом работает...

Сообщение Kakaha_228 02 май 2023, 00:06

1max1 писал(а):Ты точно не вчера начал юнити изучать?

Кстати тот самый эффект памяти снова вернулся. Я код даже ещё отредактировать не успел (времени не было) и буквально минут через 40 после вставки твоего варианта вновь появился тот самый эффект памяти. В общем, думаю пока разделить интерактив на отдельеные части, дабы он между собой не конфликтовал. Хотя больше всего странно то, что что данную систему интерактива я использую в нескольких других проектах и там такой проблемы и в помине не было (и не да Бог будет)...
Да не нужна мне подпись...
Аватара пользователя
Kakaha_228
UNIт
 
Сообщения: 60
Зарегистрирован: 21 фев 2021, 14:12

Re: NullReferenceException, при этом работает...

Сообщение 1max1 02 май 2023, 00:10

Не надо относится к коду как к какой-то алхимии или магии, все четко предопределено, то что написал то и будет. Расставляй логи ищи референсы, находи причину, это все элементарно, в твоем случае так уж точно. Посмотри где у тебя включается этот индикатор, возможно это происходит не в одном скрипте (или не в одном месте).
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: NullReferenceException, при этом работает...

Сообщение Kakaha_228 02 май 2023, 11:56

1max1 писал(а):Посмотри где у тебя включается этот индикатор, возможно это происходит не в одном скрипте (или не в одном месте).

Это проверил в первую очередь. Он включается на двух камерах: камера игрока и камера от первого лица в машине. Когда камера игрока активна, камера в машине отключается(не объект, а компонент), а вместе с ней отключается Audio Listener и скрипт интерактива. А когда игрока садится в машину, всё переключается наоборот. И это уже проверено, всё работает как задано...
1max1 писал(а):то что написал то и будет. Расставляй логи

В скрипте Item в методе Interaction всё выгляит так:
Синтаксис:
Используется csharp
public void Interaction()
        {
                if (type == ItemType.Box)
                {
                        flag = !flag;
                        GetComponent<EventSound>().VoidEventSound();
                        GetComponentInParent<Animator>().SetBool("Open", flag);
                        GetComponentInParent<Animator>().SetBool("Close", !flag);
                }
                if (type == ItemType.PickUp)
                {
                        GetComponent<EventSound>().VoidEventSound();
                        StartCoroutine(DestroyGameObject());
                }
                if(type == ItemType.Switcher)
                {
                        GetComponent<EventSound>().VoidEventSound();
            if (prov)
            {
                prov = false;
                for (int i = 0; i < ToDisable.Length; i++) ToDisable[i].SetActive(true);
                for (int i = 0; i < ToEnable.Length; i++) ToEnable[i].SetActive(false);
                for (int i = 0; i < ToDeactivate.Length; i++) ToDeactivate[i].SetActive(false);
            }
            else
            {
                prov = true;
                for (int i = 0; i < ToEnable.Length; i++) ToEnable[i].SetActive(true);
                for (int i = 0; i < ToDisable.Length; i++) ToDisable[i].SetActive(false);
            }
        }
                if(type == ItemType.CarEnter)
                {
                        Car.GetComponentInParent<MyCarController>().activeControl = true;
                        Car.GetComponentInParent<CameraSwitchScript>().enabled = true;
                        Player.SetActive (false);
                        CarCamera.enabled = true;
                        //ExitPose.SetActive (true);
                        StartCoroutine(ExitFromCar());
                        //EnterPose.SetActive (false);
                }
                if(type == ItemType.IsCarExit)
                {
            Car.GetComponentInParent<MyCarController>().activeControl = false;
                        Car.GetComponentInParent<CameraSwitchScript>().enabled = false;
                        Player.SetActive (true);
                        Player.transform.position = ExitPose.transform.position;
                        CarCamera.enabled = false;
                        ExitPose.SetActive (false);
                        EnterPose.SetActive (true);
                }
                if(type == ItemType.CarPaint)
                {
                        myMaterial.color = myColor;
                        GetComponent<EventSound>().VoidEventSound();
                }
                if(type == ItemType.CarOn)
                {
                        Car.GetComponentInParent<MyCarController>().isOn = true;
                        KeyOff.SetActive (false);
                        KeyOn.SetActive (true);
                        CarSounds.SetActive (true);
                        Exhaust.SetActive (true);
                        for (int i = 0; i < AnimParts.Length; i++)AnimParts[i].GetComponentInParent<Animator>().enabled = true;
                }
                if(type == ItemType.CarOff)
                {
                        Car.GetComponentInParent<MyCarController>().isOn = false;
                        KeyOff.SetActive (true);
                        KeyOn.SetActive (false);
                        CarSounds.SetActive (false);
                        Exhaust.SetActive (false);
                        for (int i = 0; i < AnimParts.Length; i++)AnimParts[i].GetComponentInParent<Animator>().enabled = false;
                }
        }

Весь прикол в том, что сейчас эффект памяти распространяется только на 2 объекта: вход и выход из машины, т.е. CarEnter и IsCarExit. По факту это просто бокс коллайдеры с тегом item с криптом item, в котором указано, что это вход/выход. Теперь эффект памяти работает так: запускаю сцену (или игру, это везе одинаково), сажусь в машину, выхожу из машины и больше не могу сесть, при этом могу завести/заглушить, открыть/закрыть все двери. То есть камера в салоне проолжает смотреть на объект выхода, по крайней мере я так думал. По этому переделал код камеры так, что если компонент камеры отключен, то трансформ камеры автоматом смотрит в нулевые координаты (т.е. прямо) и это действительно работает, если в машине переключить камеры или выйти из машины и при посадке нажать "Е" вместо экранной кнопки. Когда подумал, что вина на позе выхода, специально после того, как вышел из машины, удалил объект выхода и сел безо всяких проблем. Тогда я решил включать объект через корутину (что видно по коду), но и это не помогло, по прежнему когда сижусь в машину сразу же выхожу из неё... [curved_hands]
Вот теперь думаю, что раз дело только в выходу из машины, то сделаю вход и выход на наэкранных кнопках, т.к. в таком случае всё должно работать нормально, но это не точно...
Да не нужна мне подпись...
Аватара пользователя
Kakaha_228
UNIт
 
Сообщения: 60
Зарегистрирован: 21 фев 2021, 14:12

Re: NullReferenceException, при этом работает...

Сообщение 1max1 02 май 2023, 18:45

Вот теперь думаю, что раз дело только в выходу из машины, то сделаю вход и выход на наэкранных кнопках, т.к. в таком случае всё должно работать нормально, но это не точно...

Ты если уж решил месиво устраивать из редакторного инпута и смартфонного, то разделяй хотя бы директивами #if !UNITY_EDITOR && UNITY_ANDROID
И тестировать надо отдельно билд, отдельно редактор, либо поставить пакет device simulator чтобы эмулятор был в редакторе.
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: NullReferenceException, при этом работает...

Сообщение Alkos26Rus 02 май 2023, 20:04

Кстати тот самый эффект памяти снова вернулся

Ты хоть код скидывай финальный, что ты там поменял, а то судя по твоему опыту в программировании ты вобще может делаешь все не то и не так
Аватара пользователя
Alkos26Rus
Адепт
 
Сообщения: 1640
Зарегистрирован: 26 ноя 2020, 17:52
Откуда: Москва

Re: NullReferenceException, при этом работает...

Сообщение Kakaha_228 02 май 2023, 22:24

1max1 писал(а):либо поставить пакет device simulator чтобы эмулятор был в редакторе.

Ставил уже его, по сути та же вкладка game, но с разрешением выбранного девайса. Кстати, из реальных смартфонов, на которых я тестировал, в списке нет ни одного. По этому и удалил пакет, вообще мне от него толку ноль...

Alkos26Rus писал(а):Ты хоть код скидывай финальный, что ты там поменял

На данный момент вернулся к изначальному варианту кода

Kakaha_228 писал(а):сделаю вход и выход на наэкранных кнопках

Теперь эффект памяти пропал, вместо этого нет реакции на метод Use() у того компонента, который изначально был отключен. То есть когда сажусь в машину, тупо ничего нажать не могу из интерактивных элементов, при этом могу выйти из машины и всё будет работать...
Да не нужна мне подпись...
Аватара пользователя
Kakaha_228
UNIт
 
Сообщения: 60
Зарегистрирован: 21 фев 2021, 14:12

Re: NullReferenceException, при этом работает...

Сообщение Alkos26Rus 02 май 2023, 23:03

Kakaha_228 писал(а):Теперь эффект памяти пропал, вместо этого нет реакции на метод Use() у того компонента, который изначально был отключен. То есть когда сажусь в машину, тупо ничего нажать не могу из интерактивных элементов, при этом могу выйти из машины и всё будет работать...

наверно hit нул, у тебя же там проверка if (_hit != null)

Как ты так кодишь, как будто на кофейной гуще гадаешь). То что то появляется, то что то пропадает. Дебажить научись все и будет видно какой метод вызывается\не вызывается, какое условие работает\не работает. Либо это вобще чужой код и ты не понимаешь как там все устроено.
Аватара пользователя
Alkos26Rus
Адепт
 
Сообщения: 1640
Зарегистрирован: 26 ноя 2020, 17:52
Откуда: Москва

Re: NullReferenceException, при этом работает...

Сообщение Kakaha_228 02 май 2023, 23:05

Я всё понял! У меня руки из (полная Ж) , голова из (полная Ж) и мозги в (полная Ж)
Я перерыл код и случайно :-@ нашел решение проблемы с неотключающимся индикатором и сообщением: продублировал else с отключением на блок выше. Было так:
Синтаксис:
Используется csharp
void Update()
        {
                if (Physics.Raycast(transform.position, transform.forward, out hit, RayDist))
                {
                        if (hit.collider.tag == "Item")
                        {
                                indicator.enabled = true;
                                messageText.text = hit.collider.GetComponent<Item>().messageText;
                                if (Input.GetKeyDown(control))
                                {
                                        hit.collider.GetComponent<Item>().Interaction();
                                }
                        }
                        else
                        {
                                indicator.enabled = false;
                                messageText.text = "";
                        }
                }
    }
 

А теперь так:
Синтаксис:
Используется csharp
void Update()
        {
                if (Physics.Raycast(transform.position, transform.forward, out hit, RayDist))
                {
                        if (hit.collider.tag == "Item")
                        {
                                indicator.enabled = true;
                                messageText.text = hit.collider.GetComponent<Item>().messageText;
                                if (Input.GetKeyDown(control))
                                {
                                        hit.collider.GetComponent<Item>().Interaction();
                                }
                        }
                        else
                        {
                                indicator.enabled = false;
                                messageText.text = "";
                        }
                }
        else
        {
            indicator.enabled = false;
            messageText.text = "";
        }
    }

И даже это ещё не всё! Выяснилось, что "эффект памяти" был искусственным: у меня 2 наэкранные кнопки использования - первая для игрока, а вторая для машины. Когда активен игрок, кнопка машины неативна и наоборот. Так вот, каким-то фигом кнопка машины не отключалась и при нажатии на кнопку использовать воспроизводилось последнее действие камеры машины. Звучит не очень понятно, да я и сам толком объяснить не могу, но пока всё ясно...
В общем, вместо этого кода мне нужно чинить код переключения кнопок, впрочем это уже совсем другая история...
Да не нужна мне подпись...
Аватара пользователя
Kakaha_228
UNIт
 
Сообщения: 60
Зарегистрирован: 21 фев 2021, 14:12

Re: NullReferenceException, при этом работает...

Сообщение Kakaha_228 02 май 2023, 23:07

А решение с дублированием нашел в другом проекте с этим же кодом, там у меня как раз это продублировано. Странно что при переходе на новую версию, или же при смене платформы, эта часть кода стёрлась и я ломал голову...
Да не нужна мне подпись...
Аватара пользователя
Kakaha_228
UNIт
 
Сообщения: 60
Зарегистрирован: 21 фев 2021, 14:12

Re: NullReferenceException, при этом работает...

Сообщение Kakaha_228 02 май 2023, 23:09

Alkos26Rus писал(а):Как ты так кодишь, как будто на кофейной гуще гадаешь).

Да, я ещё далёк от идеала :ymhug:
Последний раз редактировалось Kakaha_228 02 май 2023, 23:45, всего редактировалось 1 раз.
Да не нужна мне подпись...
Аватара пользователя
Kakaha_228
UNIт
 
Сообщения: 60
Зарегистрирован: 21 фев 2021, 14:12

След.

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

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

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


cron