Продвинутый C# в Unity - События
HTML-код
- Опубликовано: 29 сен 2024
- Рассказываю про события в языке программирования C#, используемом в Unity. Их использование при создании игры поможет упростить код и сделать его более логичным и понятным, а так же облегчит создание некоторых взаимодействий.
Поддержать канал на русскоязычном Boosty: boosty.to/insa...
Или на Patreon: / insaneone
Discord-сервер канала: / discord
Группа VK: insaneo...
У меня на канале регулярно выходят новые видео с уроками по Unity и разработке игр, а так же другими интересными темами, связанными с геймдевом. Подписывайся!
Не забывай оставлять комментарий, если у тебя появились вопросы или предложения по видео :)
#Unity #CSharp #РазработкаИгр
Привет! Начал новую серию уроков, в которой рассмотрю продвинутое использование C# в Unity. Под продвинутым я понимаю не что-то сложное, а скорее способы упростить разработку, к которым приходишь с опытом создания игр. Кстати, я специально не стал в видео говорить ничего про UnityEvents, поскольку думаю показать их подробно в отдельном ролике. А новый урок по оптимизации уже скоро! :)
Дополню, UnityEvent выгоден если только один объект подписан на него, в любых других случаях он проигрывает в произовидельности остальным делигатам
видос хороший, НО вот лично мне реально пришлось "догугливать" что бы до конца разобраться ибо пример совсем плохо разобран (( НО, всё равно, спасибо) теперь я знаю чуть-чуть больше))
Несколько моментов
1) Не рассказал нормально про роль делегата в ивенте. Два слова с них не понял ничего.
2) Есть альтернатива записи ивентов, более приятная "public event Action OnKillMe;
" , одна строчка те же действие, готовое системное решения которое подходит под 90 процентов решения задач
3) Не рассказал что в ивентах можно передавать значения при вызове событий.
4) Отписка событий, это очень важно особенно в юнити. Ибо новички которые будут смотреть видос понаставляють событий, после не будут понимать чё у них вместо одной монетки даёт 4, а он просто не отписался.
Для продвинутого не очень, для начинающего мб.
для начинающего не подходит.
Да у него обычно хорошо выходит вкратце и понятно изложить смысл но тут явно слишком урезал важные моменты
урок не очем, автор урока просто кэп, а в тонкостях сам видать не шарит
лучший коммент на этом видео
+ 50% к информативности к видео)
Смысл объявления своего делегата в том, что ты можешь в делегате указать явно имена параметров и при автоматической генерации метода-обработчика события в метод будут подставлены имена параметров из явно написаного делегата. Это избавляет от необходимости каждую автоматическую генерацию обработчика события править имена его параметров. Мелочь, но добавляющая удобство разработки.
Делегаты наше все!
Крайне полезная структура, которая очень сильно порой помогает решить многие проблемы) Я так делал пошаговую игру через события, было интересно)
У меня предложение: есть игры на создание каких-либо алгоритмов (по-типу, собери действия игрока, а потом запусти и проверь, что вышло).
Мог бы ты сделать подобный ролик, где подробно бы объяснялось это?
Записал в список идей для будущих видео)
Пока что не вижу применения этого для себя,но вдруг пригодится =)
Чел, когда я узнал про такую штуку то я подумал "Почему я не сделал себе этого раньше?! Сделай и себе!")
Как минимум, гг ударили и надо изменить в интерфейсе его жизни. Да, можно каждый кадр проверять скок хп и... это не сильно ударит по производительности. Вообще. Но ты начинаешь потом еще проверки сувать в апдейты, и еще и еще. И вот тут начинаются лишние вычисления. Поэтому если 1 классу надо знать что что-то изменилось во втором, то первый создает событие и просто вызывает.
по аналогии с ютубом прикинь автор каждому будет звонить и говорить что вышел новый ролик? )
Короче топ тема. Можешь прочесть про паттерн Observer (Наблюдатель ) если я не ошибаюсь. Чуть больше гемора в начале пока прописываешь кажется, но это окупается. ;)
@@AlexStraga согласен, если нет подписчиков, то и никому звонить не надо; и если ни на кого не подписан, а так обзванивать десятки каналов ..., ладно если несколько каналов или подписчиков, то можно и позвонить, иначе будет лень набирать
@@combine_soldier напрямую поле хп меняешь или через функцию? И ию аптечка меняет?
@@combine_soldier это тема тогда)
Ещё один годный урок! Приятно и понятно. Лайк подписка не глядя!
Откуда взялся Play на 2:05???
Плохо код объясняешь.
Может я такой тупой , но абсолютно ничего не понял с вашего урока. У вас применяются как я понял лямбда выражения , вы о них ничего не сказали.
Раз подписался на событие то должен отписаться от него так же. иначе будешь ловить двойной или многоразовое срабатывание этого события из-за того что забыл от него отписаться. раз начал говорить про события то говори про нюансы тоже.
Да, про отписку стоило сказать, согласен, но никаких двойных срабатываний не будет, если правильно выстраивать архитектуру кода. Повторные срабатывания будут лишь тем, где необходимы.
Вот в примере из видео событие по сбору монет должно вызываться всегда в текущей игровой сессии. А при смене уровня они все автоматически удалятся вместе с объектами.
@@insaneone-7220 согласен зачем создавать событие и сразу после этого события отписываться, для того чтобы оно не сработало второй раз
колокол стоит, ждемс юнити ивентс
помедленнй Я пытаюсь понять
Подача супер, но хотелось больше практических применений.
Кстати, в тексте видео, небольшая ошибка: описывается одно поведение, а в показывается другое. Object.SomeEvent += OnSomeEventDo и this.AddListener(SomeEvent, OnSomeEventDo).
В первом случае, если целевой скрипт будет удален, возникнет ошибка, во втором, как раз нет.
Что-то разочарован. Ужасный код стайл. Публичные поля/свойства должны быть в Pascal Case, все private поля должны быть помечены как private, что rider делает автоматически, но ты даже с ним умудрился обкакаться) Если уж берешь какие-то компоненты с объекта (аниматор например), то явно вырази договор о том, что данный компонент обязательно должен присутствовать атрибутом RequireComponent. Очень редко, когда действительно нужно писать свой делегат, т.к. делегаты Action, Func и Predicate закрывают большинство случаев, а если нужно добавить подписку в инспекторе, то можно использовать UnityEvent. Как тут уже в комментариях отметили ничего не сказал про отписку. Для подписок и отписок принято использовать OnEnable и OnDisable, а не Awake/Start, сами гуглите почему, я хз)
Публичные поля в Unity пишутся с маленькой буквы, и если писать свои с большой, код будет неконсистентен. Не вижу ни одной причины использовать private кроме лишнего удлинения кода, я перенастроил райдер на обратный кодстайл. Сама такая возможность говорит, что нет единственно верной истины. RequireComponent не требуется, если есть своя, более удобная реализация автоматической настройки компонентов, в данном случае это просто не нужно, т.к. урок не об этом. Насчёт Action действительно стоило сказать. Про UnityEvent я уже писал в закреплённом комментарии. По поводу "я хз" - без комментариев.
@@insaneone-7220 Понял))
Скрипт стал активным, подписался, его улалили или сделали неактивным - отписался. Поэтому в onEnable/disable самое то подписки мутить.
@@insaneone-7220 Что в каком код стайле ПУБЛИЧНЫЕ поля пишутся с маленькой буквы? Что за дичь и ересть?
С github официального microsoft,
"Names of classes, methods, enumerations, public fields, public properties, namespaces: PascalCase."
@@insaneone-7220 Изучи код конвенсию от майкрософта раз пишешь на C#.
Код подольше показывай, на паузу постоянно приходится ставить
Объяснил очень плохо, для новых программистов будет непонятно, так что старайся объяснять подробнее. Само видео сделано качественно и на уровне, так что в этом молодец.)
Зачем делегат? Я пользуюсь unityevent. Там всё просто и не замороченно. И без всяких делегатов
Создаем одно событие, а подписываемся уже на другое, и вообще без предупреждения. Зачем вообще? Так мозги сломать можно.
События и делегаты, это не продвинутый С# - это база, первый класс, так сказать. Хотя, если сравнивать в среднем по больнице, то наверное да - продвинутый, так как большинство уроков по юнити в инете - детский сад, а на работе требуется хотя бы оконченное среднее
Это не нормальный рассказ старичок, больше применения нужно. Слишком отрывочно у тебя.
ролик хорошо обьясняет ЗАЧЕМ их использовать и +- КАК, но ЧТО это плохо совсем
(Заранее пардон за мой кривой русский) Спасибо, что делаешь это - твой контэнт шикарен. Мне очень помогли уроки по оптимизации. Буду и дальше смотреть этот канал)
Привет нормализации input
всё красиво Но "Не поняяятно"
когда новые видео?
Божественно подаёшь инфу))
О, димас, дарова)
Где же ты пропал? Почему у меня юнити не видит синтаксис слова "singleton"?
Потому что это в его классе, похоже, он объявлен, просто нам не показали.
спасибо за лекцию, смог написать курсач без плагиата
Вот это я понимаю, полезный видос!! Спасибо тебе!) лойс, подписка!
Огромное спасибо! Только не бросай пожалуйста, доведи до конца то, что запланировал изначально. По содержанию видео - всё великолепно! Просто и с примерами. Так держать!
Ничего не понял после делегатов. Поидее я уже юзаю Юнити Ивенты и как бы всё работает,но ты толи спешишь,то ли что я рано встал. Не понял зачем писать этот самый делегат? Я просто вешаю слушатель на создаваемое событие. MyEvent.AddListener(()=>myEventResult()); И ещё,что за Singlton на экземпляре Player? Я подобное видел только у тебя. О.о
Ну, точка зрения "я уже юзаю и вроде бы работает" говорит о том, что стоит подробнее изучить вопрос, если это интересует конечно) Обычные ивенты и юнити ивенты похожи, но это немного разные вещи. Юнити-ивенты медленнее работают, например. Обычные ивенты есть в самом C# и при переносе кода в другое приложение, смогут работать и без юнити.
В твоём примере укороченный делегат сделан через лямбду с помощью конструкции () =>. Да, так можно, но мне же надо было в уроке сказать о том, как это делается без синтаксического сахара? :)
Singleton это обычный и самый лёгкий паттерн проектирования для доступа к конкретному и единственному экземпляру объекта через статичную переменную, на канале есть видео про его.
Для понимания этого видео знать про него, в общем, не обязательно. Надеюсь, стало чуть понятнее)
@@insaneone-7220 ,вот как. Да,стало чуть яснее. Значит методы из самого языка работают быстрее чем методы которые есть в движке? О.о
Это как-то объясняется?
Как например не юзать camera.main и FindObjectsType?
Потому что это всё немного путает.
Мол,зачем тогда они вообще нужны,если только делают хуже?
На самом деле вопросов у меня много. Скорей всего потому-что я новичок в Юнити. И если не ответишь,то я пойму. Не охота лишний раз напрягать человека,которому может не интересно мне всё разжовывать.
Заранее,спасибо за предыдущий ответ.
@@tonicoders991 да, ивенты из языка быстрее тех, что в движке. Можно конечно это объяснить тем, что ивенты из юнити удобнее и доступны ещё и из редактора, но на самом деле это не объясняет их медлительности. Возможно, команда юнити недостаточно хорошо их реализовала.
Можно юзать UnityAction чтобы не создавать виды делегатов. Сразу например пишешь UnityAction и не паришься. event вроде нужен чтобы это событие мог вызвать только класс внутри которого он находится.
И да, ты не сказал что крайне важно не забывать отписываться от события, иначе хана потом памяти будет)
Да, вариант с UnityAction (Или просто Action, который в namespace System есть) даже удобней в основном. А насчёт отписки - если классы с ивентами или классы-подписчики уничтожаются, то в целом ничего фатального если не отписаться не произойдёт, например после смены уровня все не-статик ивенты пропадут. А вот статики отписывать в строгом порядке, если они существуют)
@@insaneone-7220 поэтому не лениться и отписываться всегда)
это же гениально, я в своих скриптах делал ссылки на другие скрипты потом вручную их вставлял куда надо, теперь могу сделать это намного проще
Скажите пожалуйста, может кто-нибудь знает где найти уроки или объяснения для тупых про то как использовать атласы, с примерами и вот это вот всё. Ато я уже 3-й день ничего выкурить не могу. Вот не лезет мне эта инфа в голову и всё.
Офигенчик👍
Какие люди в Голливуде)
День добрый ! Интересно с вами пообщаться на тему совместной работы над проектом...
ZENJECT/UNIRX нет годных видеоуроков, только от infalable labs но там без примеров нормальных (:
та
мог бы код не дергать сторону увеличения и уменьшения
что такое singleton. у меня ошибка "event1" не содержит определение для "singleton". [Assembly-CSharp]
Создай SerializedField в классе и в Юнити повесь ссылку на своего игрока.
Спасибо за видос!!! Искал эту тему долго...
Спасибо за видео и объяснение
круто,спасибо!Лайк и подписка)
А есть видео про полиморфизм?
Привет, я не совсем понял суть, зачем делегаты, если используешь синголтон? можно просто сделать метод
Можно, но лучше так не делать. И синглтон лучше не использовать, вообще не использовать.. если все спроектировано нормально, необходимость в синглтонах стремится к нулю
Ты так хорошо объясняешь. Спасибо. А у меня в игре на игроке висит скрипт Interactive. Через рэйкаст это даёт игроку возможность взаимодействовать с другими объектами. Открывать сундуки, двери, подбирать предметы. Так же при подборе предмета выводится звук. Это лучше разбить на отдельные классы и Ивентв или это достаточно взаимосвязано все для одного класса? Мне просто кажется что вроде логично все, но тебе виднее. Интересно узнать твоё мнение. Заранее спасибо
С чего ты взял, что ему виднее? 😂
Пиздатый урок, продолжай в том же духе
Хорошая подача, ничего лишнего! Спасибо!
А как отписываться от событий, если на них в старте подписываемся?
Можно в OnDisable, но тогда и подписываться лучше в OnEnable. В случае подписки в Start, можно в OnDestroy попробовать.
Огромное спасибо за полезнейший материал)
Приятный голос, классная подача)
Есть вопрос по оптимизации. Делаю раннэр. Собираю мир с елементов (GroundElement) которие состоят из квадов (как шахматная доска). Пол, потолок и стены состоят из 5*6 = 30 квадов каждий (30*4 = 120 квадов в каждом GroundElement). Одновременно на сцене присутствует 24 GroundElement. Вот в чём суть. Все GroundElement меняют свою позицию по мере продвижения игрока, но квады в них относительно родительских объектов (GroundElement) остаються на месте. Это можно как-то оптимизировать (собирать мир не из квадов нельзя)? Заранее благодарю.
Dynamic batching для квадов как минимум. Возможно, такую задачу можно было бы решить шейдером, тогда вместо квадов это была бы одна модель с квадами, двигаемыми в шейдере. Но на мобильных устройствах шейдер не всегда лучший вариант, конечно) Подробнее хотелось бы знать, для чего именно используются квады, чтобы можно было ещё что-то подсказать)
@@insaneone-7220 я мог бы прислать Вам проект на почту. Если хотите можете даже сделать на него обзор с оптимизацией или чем то ещё. Что скажете?
@@ЕдуардБездухов можно попробовать) Почта в разделе "О канале" на странице канала, можно на неё отправить
Спасибо!
Канал - ТОП!
А разве UnityEvent не удобнее?
UnityEvent работает медленнее шарповых и единственное, чем он удобнее - возможность настраивать из редактора. Но если он больше нравится - ничто не мешает им пользоваться :)
@@insaneone-7220 там ещё идёт автоматическая отписка при Destroy. Так что, я так понимаю, если игра не особо нагружена, легче использовать UnityEvent, чтобы не было лишних ошибок
А событием на событие можно подписываться? Например нажать кнопку и это событие, на это событие подписано "подобрать монетку", что тоже событие и на это подписан элемент UI который отображает количество монет
Да. Самое правильное, пожалуй - в методе, подписанном на событие нажатия кнопки, вызвать другое событие. Так вызывать можно сколько угодно событий)
@@insaneone-7220 а ларчик просто открывался...
@@insaneone-7220 а ещё вопрос: а как сделал Player.singelton?
@@insaneone-7220 день добрый, присоединяюсь к вопросу. Что такое синглтон в принципе понял, но как оформить это как свойство класса?
супер. за 5 минут объяснил то что другие по полчаса разжевывают
Подача огонь. красиво.
Спасибо.
Огромное спасибо за материал!
Два дня сидела и разбирала эту тему, Ваш урок очень понятный!
Наверное единственный, кто объяснил и показал понятно и кратко.
Спасибо большое, очень доступно, подробно и сжато.