Если на поиск проблемы уходит больше 2-5 минут, то перечитать данную заметку! Возможные причины: - Очень глупая ошибка. - Rider и/или Unity-редактор сошли с ума и их нужно перезагрузить. ### Удаляется ли компонент в системе по окончанию работы системы. Каждая система перебирает в своем foreach какой-то компонент (допустим, Order). Важно проверять, удаляет ли система такой компонент по окончанию итерации. В противном случае, этот же Order будет взят системой в работу в следующем кадре и будут непредсказуемые ошибки. ### Не забывать, что Destroy(), SetActive() и прочие Unity-методы могут не срабатывать моментально Я удалял слоты-gameObjects и сразу создавал новые, а из-за того, что Unity удаляет gameobjects не сразу, а в конце кадра, то после создания новых слотов, Unity удалял все слоты, в том числе новые. ### Нет ли return, который прерывает работу кода Когда игрок нажимает на здание, появляется UI-окошко под мышкой. В момент нажатия срабатывал Input.GetMouseButtonDown(0) Но не срабатывал Input.GetMouseButtonUp(0) Я не мог понять, почему. Вроде глазами прошелся, ключевого слова return, который бы прервал выполнение кода до Input.GetMouseButtonUp, не было. Оказывается, я просто не посмотрел на начало кода. Там был return Когда игрок отпускал мышку, код прерывался в начале, так и не дойдя до Input.GetMouseButtonUp ![Читать, если возник трудноотловимый баг](Читать,%20если%20возник%20трудноотловимый%20баг.png) ### Вызывать log.info() в каждом блоке Для оперативного выявления проблем при разработке новых фич, рекомендую сразу же параллельно расставлять логи. Это позволит оперативно выявлять ошибки. - Некоторые блоки могут просто не вызываться, а ты этого не осознаешь. ### Убедиться, что система добавлена в список внутри EntityFactory Уже была создана система, но не дописана, так как я переключился на другую задачу. А когда вернулся к этой системе, то не проверил, была ли она указана в списке. Из-за этого минут 20 потерял на то, пытаясь разобраться, почему у меня неправильно работает алгоритм. ### Внимательно проверять то ли название поля/свойства/переменной. Я допустил ошибку. Обращался к свойству внутри этого же свойства, в том месте где мне нужно было обратиться к приватному полю с похожим названием. Из-за этого, в консоль выводилась ошибка: «Попытка получить значение BaseTransform до его установки» ![Читать, если возник трудноотловимый баг-1](Читать,%20если%20возник%20трудноотловимый%20баг-1.png) ### В Системах в Update внутри foreach не использовать return Случайно вместо _continue_ использовал _return_. При такой «случайности» система перестает обрабатывать сущности, если хотя бы одна сущность не проходит условие if ### Не создавать похожие названия, при котором беглый взгляд не даст увидеть разницу. Были у меня два поля - BulldozerMenu - BuildingMenu По ошибке передавал методу BuildingMenu, вместо BulldozerMenu. Не мог понять в чем проблема. ### Не создавать в системе полЯ с намерением хранить там данные для сущностей Данные обязательно должны храниться в компонентах, а не в системах, иначе будут баги из-за того, что будет постоянно происходить перезапись переменных в системах. ### Проверить Clear на наличие все полей у всех причастных компонентов Если используется пул компонентов с целью НЕ тревожить GC, то важно не забывать чистить переиспользованные компоненты от старых данных. (Иначе возникают баги) - А также убедиться в наличии base.Clear(); - Убедиться, что поле, что хранит EntityId имеет значение по умолчанию как -1. ### Проверить, не используется ли экземпляр компонента, до его получения - Если в foreach в системе что-то выполняется до RewriteFields(order), то очень важно, чтобы не использовались переменные из RewriteFields. (Иначе возникают трудноотловимые баги!) В примере ниже, в переменной _attacker хранилось значение, которое было записано в предыдущей итерации цикла foreach. ![Читать, если возник трудноотловимый баг-2](Читать,%20если%20возник%20трудноотловимый%20баг-2.png) Из-за этого возникала ситуация, что шла попытка удалить компоненты для Entity, у которого уже нет данных компонентов. Потому что он был удален в прошлой итерации. ![Читать, если возник трудноотловимый баг-3](Читать,%20если%20возник%20трудноотловимый%20баг-3.png) ### Перепроверить параметры в инспекторе У одного Хаммера в инспекторе были прописан радиус в 30, из-за чего я не мог понять, почему один из двух Хаммеров не едет за целью, а просто стреляет на месте. (Внимательно перепроверять параметры в инспекторе!) ### Проверить с той ли сущностью выполняются операции Важно проверять, у какого Entity вызывается тот или иной метод. Я допустил ошибку и ждал эвента у жертвы на изменение компонента «приказ на агрессию». Хотя этот компонент должен быть у агрессора, а не у жертвы. ![Читать, если возник трудноотловимый баг-4](Читать,%20если%20возник%20трудноотловимый%20баг-4.png) ### Убедиться, что ты точно понимаешь в какой последовательности выполняется код При поиске бага, важно перепроверить последовательность выполнения систем. Транспорт продолжал ехать в первоначально заданную точку, не смотря на то, что я дал новую команду на атаку. Проблема оказалась в том, что я забыл о последовательности систем. Сначала первая система вычисляла путь, а вторая уже ехала по массиву точек. Я пытался найти проблему во второй системе, забыв про первую. ### Верно ли указаны дженерики при подписке? Перепроверять, что подписка на событие правильна указана. Не забывать, что при добавлении новой подписки в систему, нужно добавить метод CheckingSubscription ![Читать, если возник трудноотловимый баг-5](Читать,%20если%20возник%20трудноотловимый%20баг-5.png) # Проблемы при отладке в ECS Очень сложно было отловить баг. Вылезал Fatal error о том, что AddC пытается добавить компонент HitEventC, который уже существует у Entity. Я не понимал в чем проблема, потому что перед запуском foreach была полная чистка всех HitEventC. ![Читать, если возник трудноотловимый баг-6](Читать,%20если%20возник%20трудноотловимый%20баг-6.png) А AddC был внутри foreach ![Читать, если возник трудноотловимый баг-7](Читать,%20если%20возник%20трудноотловимый%20баг-7.png) Спустя час-два до меня дошло, что это цикл, в котором двигаются снаряды в сторону цели. Значит, если в цикле два снаряда долетают одновременно до цели, то идет попытка добавить HitEventC дважды в разных итерациях.(Снаряды одновременно долетали из-за другого бага. Суть бага - якобы снаряды одновременно долетали до цели, хотя по факту этого не было).