Просто о событиях в Unity, используя делегаты Action, Func и шину событий (EventBus). События с параметрами и возвращаемым значением. Discord: / discord
Работаю над проектом и решил оживить в памяти изученные события так как нужно использовать именно их, а тут на тебе все разжованно! Посмотрел и оживил в памяти все что нужно! Спасибо тебе большое!
Вот оно - видео, которое дало начальное понимание о события в Unity!! Много разного пытался прочитать, посмотреть, но что-то все равно не лезло в голову, много вопросов оставалось. А в этом видео я услышал ответы на все эти вопросы. Спасибо за труды! 🔥👍
Это именно то, что мне было нужно. Всё, на чем ты сделал акценты, было не напрасно. Ответил на кучу вопросов, возникших в попытках разобраться. (Про разные варианты записи, про статику, про то зачем события, если можно просто указать ссылку на объект и тд). Спасибо большое за отличное объяснение.
Могу посоветовать присоединиться к нашему дискорду (в описании канала есть ссылка) - общение с единомышленниками сильно повышает шансы на понимание многих тем)
Це найкращий гайд по івентам який я бачив, я боявся цих івентів все своє життя, а тут оказується, якщо гарно пояснити - то і я зрозумію, дякую та респект автору!
Топ контент по юнити, просто огромное спасибо. Недавно досмотрел шарп на основе юнити по курсу Сакутина и начал искать себе материал для изучения юнити и наткнулся на этот канал - по юнити лучше пока что ничего не нашел. Спасибо огромное!
Спасибо очень пригодилось. Я делаю игру на дипломный проект, и при заходе игрока в сессию мне нужно обновлять список игроков поэтому в сценарии где происходит обновлении списка я подписываюсь и очень хорошо работает.
Посмотрел видео про события и решил посмотреть что за канал и заодно подписаться, а тут херак я почти все видео просмотрел с туториалами но без подписки а за счет предложке ютуба)) Срочно исправил данный баг.
I've looked for english sources first, and there are not many good tutorials about Func. But even if i know a little russian, i got what the func is finally.
Привет автор. хорошие видосы у тебя ! не мог бы ты снять видос про урон одного объекта другому обойдя необходимость использования "тяжелого" GetComponent? сначала думал, что помогут события и слабая связность кода. но по мучавшись несколько дней, понял, что тут вопрос в архитектуре а не в связности компонентов. ))
Привет) Я не особо в этом разбираюсь, но не думаю, что GetComponet - это такая уж тяжёлая операция - всего-то сравнить типы компонентов на объекте, а их обычно не так много (Transform, SpriteRenderer, Animator, AudioSource, Collider и какой-нибудь скрипт). Другое дело - это свести к минимуму все эти поиски, т.е. чтобы искать не у всех объектов нужный компонент, а лишь у тех, у которых он может находиться. У меня обычно есть один-два слоя для врагов, и разрушаемых предметов. Так же есть интерфейс типа IDamageable, у которого есть метод TakeDamage(int value). И во время нанесения удара, на короткий момент я проверяю попали ли под удар объекты на слое, а потом уже ПЫТАЮСЬ найти компонент у нужных объектов: Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, damageRadius, damagebleLayers); if (colliders == null) { return; } foreach (Collider2D col in colliders) { if (col.gameObject.TryGetComponent(out IDamageable iDamage)) { iDamage.TakeDamage(damageValue); } } То же самое можно делать и с рейкастами и при коллизиях. А можно и вовсе искать не интерфейс, а необходимый скрипт.
Привет. Спасибо за видео. Но у меня философская проблема. Ты привел хороший пример, когда на сцене 100 врагов, и надо нанести урон конкретному. Я хочу сделать это через событийную модель, где все 100 врагов подписаны на событие нанесения урона. Но неужели мне у каждого врага надо проверять "меня ли ударили?". Я не совсем понимаю, как бы сделать оптимизированно так, чтобы событие получения урона вызывалось у конкретного врага среди множества... (без лишних 100 `if`, которые тратят драгоценные такты процессора) Также я подозреваю, что есть несколько ограничений: 1) Лучше не использовать UnityEvent, потому что он в несколько раз медленнее встроенных C#-событий 2) Лучше не использовать GetComponent в менеджере событий, потому что это дорогой вызов, который обходит всё дерево компонентов объекта
При количестве возвращающих тип сущностей больше одной, от Func, и подозреваю, от Predicate толку никакого (если требуется выборка). Реальный пример - нужно вернуть Transform по имени поля. Имя поля - естественно enum. Сравниваем, возвращаем.К примеру имеется десять сущностей, нужный где то посередине. Ставим условие, что остальные вернут null, т.к. возвращаемый метод обязан в любом случае что то вернуть. Так вот, в этом случае вернется null. Его вернет последняя сущность, не овечающая условию. Плюнул, переделал обратно на старый надежный Action.
Спасибо за подсказку со статическим событием, тоже столкнулся с неудобством, что нужно Игроку подписываться на события, когда Враг попадает по игроку 2 руками и 2 ногами(что бы у игрока отнять ХитПоинты) т.е это 4 подписки, а если врагов 10, это уже делать 40 подписок. Да, можно без событий при попадании получать скрипт Игрока и вызывать метод УменшитьХитПоинты. Как правильнее? Тут я озадачился, когда использование событий является лишним, а когда необходимым...?
Обычно, описанную Вами ситуацию решают вообще без событий) А например через интерфейсы. Но если в игре урон будет получать только перс (или перс и всего один-два типа врагов), то можно и вовсе без интерфейсов. У игрока делается публичный метод, например: public void TakeDamage (int value) { health -= value; // а дальше обычно идёт проверка: если здоровье перса ниже нуля, то... отключение, дестрой или что хотите. } А у самих врагов в методах проверки коллизий или триггеров ищется класс игрока и вызывается метод нанесения урона. Например, если скрипт, отвечающий за здоровье и урон у игрока, назван как "HeroHealth": private void OnTriggerEnter2D(Collider2D collision) { if (collision.gameObject.TryGetComponent(out HeroHealth heroHealth)) { heroHealth.TakeDamage(20); // где в скобках передаётся величина урона. } }
Лучше в OnDisable, так как при удалении объекта (onDestroy) всё равно будет сначала вызван onDisable. А в обратную сторону такое не сработает. Похожая ситуация и при создании объекта - в нём будет вызван onEnable. Так что связка onEnable / onDisable, на мой взгляд самая надёжная)
Помогите пожалуйста! У меня есть несколько врагов. Я стреляю по ним из автомата(стрельба сделана с помощью рэйкаста) и по ним наносится урон при попадании. Однако урон наносится сразу всем врагам а не одному, хотя я остальных не трогал.
Точно знать не могу, но сдаётся мне, что у Вас переменная, в которой хранится здоровье врага, имеет модификатор доступа "static", в таком случае это переменная будет общей для всех экземпляров класса (копий врага). На 4:28 я именно об этом и говорил)
кто хочет делать игру в unity? все подробности расскажу в лс, но надо под комментарием написать +. Нужны:художники, аниматоры, кодер еще один, музыкант(писать музыку под фон и короткие звучания)
Два раза пересмотрел лекцию из GB по теме делегатов и событий - нихрена не понял. Заютубил, нашел это видео на 11 минут. Понял. Как это блин работает?)
На самом деле это тема на несколько видео. В планах конечно же они есть. Но в комментариях нам с вами не хватит нервов, чтобы и объяснить, и понять) Так что советую посмотреть других авторов (т.к. у меня не знаю, когда затронутся эти темы), например, у Brackeys я, кажется, видел и стрельбу и удары, рекомендую: ua-cam.com/users/Brackeysvideos
Как на 10:45 у меня так событие не инвокается, компилятор не дает. Пишет, что событие EventBus.OnTest может присутствовать только в левой части выражания перед -= и +=. Инвокается только в самом классе EventBus. Поэтому приходится под каждое событие в EventBus метод создавать для вызова, и к нему уже обращаться при надобности
Это происходит потому что в видео не используется ключевое слово event - это даёт возможность вызвать делегат из другого класса. Однозначно, Ваш способ корректнее и потенциально может вызвать меньшее количество ошибок и исключений!, просто способ описанный в видео более гибкий и, сугубо на мой взгляд, не плохо подходит для беглого ознакомления с делегатами и быстрого использования в любительских проектах.
Автор прошу тебя помочь! Может кто мне обяснить? Как это возможно создать событие в одном классе, а вызвать его в другом? У меня студия ругается и не дает вызвать. Пробовал все переписать один в один и ничего. Искал решение в инете, говорят что событие вызывается только в классе где он был создан.
Возможно, что я Вас запутал... Потому что под событиями может подразумеваться, как вызов делегата, так и само событие. В видео я использую встроенные делегаты, такие как Action и Func. Если Вы объявите их без ключевого слова event, то сможете вызвать так же, как события, но из любого класса. По сути - это будет событие, но по факту - это просто делегат (даже молнии не будет в студии, а просто как поле будет подсвечиваться)
Привет! Не, к сожалению я до мультиплеера всё никак не доберусь. У нас на дискорд-сервере (в шапке есть ссылка) есть пару проектов, в которых ребята в онлайн пытаются, но там вроде Mirror мелькал, но может они смогут подсказать...
Могу ошибаться, но в Awake такое не делают) Потому что нет гарантий, что вызов события произойдёт после инициализации класса в котором описан делегат. Awake вызывается первым при активации объекта (какой объект вызовется раньше не понятно), поэтому в Awake можно получить компоненты с самого себя, скажем там найти Аниматор или SpriteRenderer, а вот получать те же компоненты с другого объекта лучше из Start (т.е. гарантированно после того, как активируется целевой объект). Рассказал, как мог, уж простите, сам со всеми тонкостями не знаком, но думаю Вам это будет интересно: docs.unity3d.com/Manual/ExecutionOrder.html или старый вариант на русском docs.unity3d.com/ru/530/Manual/ExecutionOrder.html
@@NoobGameDev то есть, если например я хочу найти компонент через FindObjectOfType(); то лучше его засунуть в Start() а не в Awake(), так как, класс игрока в этот момент может быть не создан?
@@danismingaleev4686 Да, всё верно (экземпляр класса). Это у Вас может случайно сработать, но нет гарантий, что сработает на другом компе или после изменений в Иерархии. По крайней мере, я так понимаю работу движка)
Так я, вроде и не обещал, что покажу 😅 Статики вещь не плохая. Просто Вы много смотрите Романа Сакутина)) Я согласен, что не стоит их писать для каждой переменной (в видео есть пример), но в случае с делегатами, это вообще мегаудобная штука, учитывая, что событие обычно единственное в своём роде и доступное из любого места проекта.
Привет. Спасибо за видео. Но у меня философская проблема. Ты привел хороший пример, когда на сцене 100 врагов, и надо нанести урон конкретному. Я хочу сделать это через событийную модель, где все 100 врагов подписаны на событие нанесения урона. Но неужели мне у каждого врага надо проверять "меня ли ударили?". Я не совсем понимаю, как бы сделать оптимизированно так, чтобы событие получения урона вызывалось у конкретного врага среди множества... (без лишних 100 `if`, которые тратят драгоценные такты процессора)
А зачем так делать?) Зачем всем противникам знать, что кого-то ударили, а потом проверять не его ли случаем?) Обычно всё проще - через коллайдеры, триггеры, рейкасты, оверлапы. Любым из этих способов можно вызвать какой-нибудь метод TakeDamage (который будет одинаковым у всех врагов) и в итоге урон получит тот противник, по которому попала пуля, ударила палка и прочее. Единственное для чего может понадобиться всем врагам знать о том, что кого-то бьют - это чтобы получить координаты того, кого ударили, чтобы сагриться и помчаться к месту нахождения обидчика))
@@NoobGameDev спасибо за ответ. Меня от этих способов останавливало то, что Jetbrains Rider подчеркивал мне "красным" методы GetComponent, SendMessage, Broadcast и т.д. Наверное, потому что у меня нажатие кнопок отслеживается в Update, и IDE понимает, что эти дорогие методы вызываются каждый кадр. Тогда переделаю input на новую событийную модель в Юнити, надеюсь получится выжать что-нибудь! Но меня не покидает мысль, что устройство будет "тупить", что я каждый раз вызываю collider.GetComponent - который заново обходит дерево 🌲 компонентов и ищет нужный. Особенно это тупо, когда стреляешь из автоматического оружия с высокой скоростью. Ох, горе мне горе! Надо придумать как это всё закешировать
@@nomadirl3380 Я бы сделал так. У пули есть скрипт, в котором при коллизии она будет проверять есть ли на объекте с которым она столкнулась скрипт противника и если есть, то вызывает в нём метод, который наносит врагу урон. Примерно так это может выглядеть, если скрипт врага будет называться EnemyDamage, а метод в нём, который будет наносить сам урон - TakeDamage: private void OnCollisionEnter2D(Collision2D collision) { if (collision.gameObject.TryGetComponent(out EnemyDamage enemy)) { enemy.TakeDamage(damageValue); } Destroy(gameObject); // уничтожение пули }
@@NoobGameDev спасибо за твой пример. В большинстве случаев он решает все проблемы, но я напишу несколько нюансов для тех, кто будет читать эту ветку комментариев: 1) иногда пули (объекты) летят слишком быстро, и при низкой частоте кадров не соприкасаются с коллайдерами - в след. кадре пуля как бы уже за целью, хотя в предыдущем была перед ней 2) иногда дешевле стрелять "лучами", а не пулями (объектами); также у лучей можно указать layerMask - слой объектов, например Damagable, у которых гарантировано будут MyScript, и их коллайдер не придется проверять через if 3) Методы семейства GetComponent - дорогие, потому что каждый раз выполняют поиск нужного компонента среди всех компонентов объекта. Их не стоит использовать в цепочке Update()
@@nomadirl3380 Со 2 и 3-м пунктом полностью согласен) А для решения первого есть простое, но не самое дешёвое (но и не прям уж дорогущее) решение: если на объекте, будь то пуля или противник есть Rigidbody, то можно изменить просчёт коллизий (Collision Detection) с Discrete на Continuous. Ну, и то, что они пролетаю сквозь коллайдеры не зависит от частоты кадров, так как у FixedUpdate, OnTriggerXXX, OnCollisionXXX, просчёт происходит через фиксированный промежуток времени (0.02 сек. по умолчанию) и не зависит от того насколько быстро обновляются кадры. Я могу, конечно, где-то ошибаться, но вроде бы так))
Реально респект, наконец-то я нашёл достойный ролик по этой теме!!!
Идеальный урок! Спасибо. Очень помог. Мне события сложно было понять, а к Action я вообще боялся притрагиваться.
Респект автору! прям огромный, столько туториалов пересмотрел и только тут наконец понял что к чему
Спасибо! Это и было моей целью)
я такая же х-ня
same
+++
Обалдеть. Я зря все это время думал над тем, как связать свой GameManager с существующими монстрами!!! Спасибо за гайд!!
Это самый шикарный урок. Все встало на свои места, спасибо!
я тоже хочу выразить большую благодарность за прекрасно поданный материал.
Блин реально это наверное самый понятный туториал)) Спасибо большое))
Самое понятное объяснение, спасибо!!!
Работаю над проектом и решил оживить в памяти изученные события так как нужно использовать именно их, а тут на тебе все разжованно! Посмотрел и оживил в памяти все что нужно! Спасибо тебе большое!
Вот оно - видео, которое дало начальное понимание о события в Unity!!
Много разного пытался прочитать, посмотреть, но что-то все равно не лезло в голову, много вопросов оставалось. А в этом видео я услышал ответы на все эти вопросы. Спасибо за труды! 🔥👍
Это именно то, что мне было нужно. Всё, на чем ты сделал акценты, было не напрасно. Ответил на кучу вопросов, возникших в попытках разобраться. (Про разные варианты записи, про статику, про то зачем события, если можно просто указать ссылку на объект и тд). Спасибо большое за отличное объяснение.
Спасибо за объяснения. Пока хорошо понял только о static ) но видео очень интересное, когда-то пойму и всё остальное
Могу посоветовать присоединиться к нашему дискорду (в описании канала есть ссылка) - общение с единомышленниками сильно повышает шансы на понимание многих тем)
Це найкращий гайд по івентам який я бачив, я боявся цих івентів все своє життя, а тут оказується, якщо гарно пояснити - то і я зрозумію, дякую та респект автору!
Топ контент по юнити, просто огромное спасибо. Недавно досмотрел шарп на основе юнити по курсу Сакутина и начал искать себе материал для изучения юнити и наткнулся на этот канал - по юнити лучше пока что ничего не нашел. Спасибо огромное!
Очень удобно. Разжовано, но для понимания так и нужно. То что разжевано - это комплимент.
Спасибо за урок, всё понял!!!
Полезный видос. Я много видео громоздких смотрел на эту тему, первый раз вижу такое объяснение. Респект автору)
Спасибки!
Спасибо за твою работу, очень помог !
Спасибо, очень доступно всё объясняешь
Спасибо очень пригодилось. Я делаю игру на дипломный проект, и при заходе игрока в сессию мне нужно обновлять список игроков поэтому в сценарии где происходит обновлении списка я подписываюсь и очень хорошо работает.
Спасибо! Очень доходчиво.
Спасибо, отличное видео.
Спасибо, лучше всех объяснил! 😘
Посмотрел видео про события и решил посмотреть что за канал и заодно подписаться, а тут херак я почти все видео просмотрел с туториалами но без подписки а за счет предложке ютуба)) Срочно исправил данный баг.
Благодарен))
спасибо большое! очень хорошо объяснил все
Пожалуй самое понятное видео по данной теме
Хороший материал! Достойно )
Вроде вдуплил, осталось реализовать в существующем проекте и точно пойму.
Спасибо ❤️
огромное спасибо. только с твоей помощью разобрался. но в конце пришлось скорость на 0.75 ставить)))
Спасибо за видео.
Спасибо, чувак, очень помог
Супер
Топ объяснение
Блин пасиба тебе ща все очень помог!
От души, за видео!
Спасибо!!!
Я понял события, спасибо чеелл)))
Наконец то новое видео
спасибо большое
суппер! спасибо!
Привет тёска, давно тя не было слышно, с наступившим, всех благ, 👍👍👍
Привет) Появилось времени немного - решил напомнить о себе)) Спасибо, взаимно!) 👍
Выдайте автору медаль за труд!
Спасибо!
Хоть кто то проговорил про необходимость отписки от делегатов.
только здесь понял 🎉
I've looked for english sources first, and there are not many good tutorials about Func. But even if i know a little russian, i got what the func is finally.
Wow! I'm glad I could help you in some way. This is inspiring, thanks)
Это хороший. Даже кишка не выпала
Привет автор. хорошие видосы у тебя ! не мог бы ты снять видос про урон одного объекта другому обойдя необходимость использования "тяжелого" GetComponent? сначала думал, что помогут события и слабая связность кода. но по мучавшись несколько дней, понял, что тут вопрос в архитектуре а не в связности компонентов. ))
Привет) Я не особо в этом разбираюсь, но не думаю, что GetComponet - это такая уж тяжёлая операция - всего-то сравнить типы компонентов на объекте, а их обычно не так много (Transform, SpriteRenderer, Animator, AudioSource, Collider и какой-нибудь скрипт).
Другое дело - это свести к минимуму все эти поиски, т.е. чтобы искать не у всех объектов нужный компонент, а лишь у тех, у которых он может находиться.
У меня обычно есть один-два слоя для врагов, и разрушаемых предметов. Так же есть интерфейс типа IDamageable, у которого есть метод TakeDamage(int value).
И во время нанесения удара, на короткий момент я проверяю попали ли под удар объекты на слое, а потом уже ПЫТАЮСЬ найти компонент у нужных объектов:
Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, damageRadius, damagebleLayers);
if (colliders == null) { return; }
foreach (Collider2D col in colliders)
{
if (col.gameObject.TryGetComponent(out IDamageable iDamage))
{
iDamage.TakeDamage(damageValue);
}
}
То же самое можно делать и с рейкастами и при коллизиях. А можно и вовсе искать не интерфейс, а необходимый скрипт.
@@NoobGameDev спасибо что, так детально ответили !)
👍
Хорош! Спасибо))
Привет. Спасибо за видео. Но у меня философская проблема. Ты привел хороший пример, когда на сцене 100 врагов, и надо нанести урон конкретному. Я хочу сделать это через событийную модель, где все 100 врагов подписаны на событие нанесения урона. Но неужели мне у каждого врага надо проверять "меня ли ударили?". Я не совсем понимаю, как бы сделать оптимизированно так, чтобы событие получения урона вызывалось у конкретного врага среди множества... (без лишних 100 `if`, которые тратят драгоценные такты процессора)
Также я подозреваю, что есть несколько ограничений:
1) Лучше не использовать UnityEvent, потому что он в несколько раз медленнее встроенных C#-событий
2) Лучше не использовать GetComponent в менеджере событий, потому что это дорогой вызов, который обходит всё дерево компонентов объекта
Не нужно делать получение урона конкретным врагом через события.
При количестве возвращающих тип сущностей больше одной, от Func, и подозреваю, от Predicate толку никакого (если требуется выборка). Реальный пример - нужно вернуть Transform по имени поля. Имя поля - естественно enum. Сравниваем, возвращаем.К примеру имеется десять сущностей, нужный где то посередине. Ставим условие, что остальные вернут null, т.к. возвращаемый метод обязан в любом случае что то вернуть. Так вот, в этом случае вернется null. Его вернет последняя сущность, не овечающая условию. Плюнул, переделал обратно на старый надежный Action.
Спасибо за подсказку со статическим событием, тоже столкнулся с неудобством, что нужно Игроку подписываться на события, когда Враг попадает по игроку 2 руками и 2 ногами(что бы у игрока отнять ХитПоинты) т.е это 4 подписки, а если врагов 10, это уже делать 40 подписок.
Да, можно без событий при попадании получать скрипт Игрока и вызывать метод УменшитьХитПоинты. Как правильнее? Тут я озадачился, когда использование событий является лишним, а когда необходимым...?
Обычно, описанную Вами ситуацию решают вообще без событий) А например через интерфейсы. Но если в игре урон будет получать только перс (или перс и всего один-два типа врагов), то можно и вовсе без интерфейсов.
У игрока делается публичный метод, например:
public void TakeDamage (int value)
{
health -= value;
// а дальше обычно идёт проверка: если здоровье перса ниже нуля, то... отключение, дестрой или что хотите.
}
А у самих врагов в методах проверки коллизий или триггеров ищется класс игрока и вызывается метод нанесения урона. Например, если скрипт, отвечающий за здоровье и урон у игрока, назван как "HeroHealth":
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.TryGetComponent(out HeroHealth heroHealth))
{
heroHealth.TakeDamage(20); // где в скобках передаётся величина урона.
}
}
: )
( :
Привет, твой гайд как сделать платформер топ!, можно гайд как кнопки добавить для телефона?!!
Спасибо за видео) А где лучше отписываться от события?
Лучше в OnDisable, так как при удалении объекта (onDestroy) всё равно будет сначала вызван onDisable. А в обратную сторону такое не сработает.
Похожая ситуация и при создании объекта - в нём будет вызван onEnable.
Так что связка onEnable / onDisable, на мой взгляд самая надёжная)
@@NoobGameDev окей, пасибо)
Помогите пожалуйста! У меня есть несколько врагов. Я стреляю по ним из автомата(стрельба сделана с помощью рэйкаста) и по ним наносится урон при попадании. Однако урон наносится сразу всем врагам а не одному, хотя я остальных не трогал.
Точно знать не могу, но сдаётся мне, что у Вас переменная, в которой хранится здоровье врага, имеет модификатор доступа "static", в таком случае это переменная будет общей для всех экземпляров класса (копий врага). На 4:28 я именно об этом и говорил)
кто хочет делать игру в unity? все подробности расскажу в лс, но надо под комментарием написать +. Нужны:художники, аниматоры, кодер еще один, музыкант(писать музыку под фон и короткие звучания)
Два раза пересмотрел лекцию из GB по теме делегатов и событий - нихрена не понял. Заютубил, нашел это видео на 11 минут. Понял. Как это блин работает?)
Как сделать стрельбу и удар в 2д игре? Расскажи пожалуйста.
На самом деле это тема на несколько видео. В планах конечно же они есть. Но в комментариях нам с вами не хватит нервов, чтобы и объяснить, и понять) Так что советую посмотреть других авторов (т.к. у меня не знаю, когда затронутся эти темы), например, у Brackeys я, кажется, видел и стрельбу и удары, рекомендую: ua-cam.com/users/Brackeysvideos
Как на 10:45 у меня так событие не инвокается, компилятор не дает. Пишет, что событие EventBus.OnTest может присутствовать только в левой части выражания перед -= и +=. Инвокается только в самом классе EventBus. Поэтому приходится под каждое событие в EventBus метод создавать для вызова, и к нему уже обращаться при надобности
Это происходит потому что в видео не используется ключевое слово event - это даёт возможность вызвать делегат из другого класса. Однозначно, Ваш способ корректнее и потенциально может вызвать меньшее количество ошибок и исключений!, просто способ описанный в видео более гибкий и, сугубо на мой взгляд, не плохо подходит для беглого ознакомления с делегатами и быстрого использования в любительских проектах.
ферштейн
Автор прошу тебя помочь! Может кто мне обяснить? Как это возможно создать событие в одном классе, а вызвать его в другом? У меня студия ругается и не дает вызвать. Пробовал все переписать один в один и ничего. Искал решение в инете, говорят что событие вызывается только в классе где он был создан.
Возможно, что я Вас запутал... Потому что под событиями может подразумеваться, как вызов делегата, так и само событие. В видео я использую встроенные делегаты, такие как Action и Func. Если Вы объявите их без ключевого слова event, то сможете вызвать так же, как события, но из любого класса.
По сути - это будет событие, но по факту - это просто делегат (даже молнии не будет в студии, а просто как поле будет подсвечиваться)
а как же UnityEvent ?
Привет.Ты случаем не прльзовался Photon pun?если да,то не знаешь как сделать список серверов в игре?ни одного нормального видео не нашел
Привет! Не, к сожалению я до мультиплеера всё никак не доберусь. У нас на дискорд-сервере (в шапке есть ссылка) есть пару проектов, в которых ребята в онлайн пытаются, но там вроде Mirror мелькал, но может они смогут подсказать...
Вызов события (Invoke) почему-то не работает в методе Awake, но работает в методе Start 😒
Могу ошибаться, но в Awake такое не делают) Потому что нет гарантий, что вызов события произойдёт после инициализации класса в котором описан делегат. Awake вызывается первым при активации объекта (какой объект вызовется раньше не понятно), поэтому в Awake можно получить компоненты с самого себя, скажем там найти Аниматор или SpriteRenderer, а вот получать те же компоненты с другого объекта лучше из Start (т.е. гарантированно после того, как активируется целевой объект). Рассказал, как мог, уж простите, сам со всеми тонкостями не знаком, но думаю Вам это будет интересно:
docs.unity3d.com/Manual/ExecutionOrder.html
или старый вариант на русском docs.unity3d.com/ru/530/Manual/ExecutionOrder.html
@@NoobGameDev то есть, если например я хочу найти компонент через FindObjectOfType(); то лучше его засунуть в Start() а не в Awake(), так как, класс игрока в этот момент может быть не создан?
@@danismingaleev4686 Да, всё верно (экземпляр класса). Это у Вас может случайно сработать, но нет гарантий, что сработает на другом компе или после изменений в Иерархии. По крайней мере, я так понимаю работу движка)
лучший нуб
А сколько тебе лет мне просто интересно по голосу тебе лет 25
Недотягиваю получается) Мне 29.
Чиииилл
Ещё быстрее, пожалуйста, а то некоторые слова можно понять
Всем привет ищу друга для совместного создания игр и обучения юнити, опыт не важен
Я не могу подписатся из-за лимита(
Ты сказал про проблему статики, а как круто избавиться не показал(
Так я, вроде и не обещал, что покажу 😅 Статики вещь не плохая. Просто Вы много смотрите Романа Сакутина)) Я согласен, что не стоит их писать для каждой переменной (в видео есть пример), но в случае с делегатами, это вообще мегаудобная штука, учитывая, что событие обычно единственное в своём роде и доступное из любого места проекта.
@@NoobGameDev не знаю причем тут сакутин, проблему про инкапсуляцию подняли вы)
@@OneKekc что такое инкапсуляция в твоем понимании?
@@firewatch123 свойство кода, которое не позволяет пьяному чинить кофемашину, потому что на ней замок)
Как-то слишком быстро объясняете, не понятно, как работает, сложно разобраться. Может быть, просто я тупой.
Но лайк поставил, в целом, урок хороший.
Не тупой, просто урок не для новичков
закрываю видео когда слышу про геймменеджер
Привет. Спасибо за видео. Но у меня философская проблема. Ты привел хороший пример, когда на сцене 100 врагов, и надо нанести урон конкретному. Я хочу сделать это через событийную модель, где все 100 врагов подписаны на событие нанесения урона. Но неужели мне у каждого врага надо проверять "меня ли ударили?". Я не совсем понимаю, как бы сделать оптимизированно так, чтобы событие получения урона вызывалось у конкретного врага среди множества... (без лишних 100 `if`, которые тратят драгоценные такты процессора)
А зачем так делать?) Зачем всем противникам знать, что кого-то ударили, а потом проверять не его ли случаем?) Обычно всё проще - через коллайдеры, триггеры, рейкасты, оверлапы. Любым из этих способов можно вызвать какой-нибудь метод TakeDamage (который будет одинаковым у всех врагов) и в итоге урон получит тот противник, по которому попала пуля, ударила палка и прочее.
Единственное для чего может понадобиться всем врагам знать о том, что кого-то бьют - это чтобы получить координаты того, кого ударили, чтобы сагриться и помчаться к месту нахождения обидчика))
@@NoobGameDev спасибо за ответ. Меня от этих способов останавливало то, что Jetbrains Rider подчеркивал мне "красным" методы GetComponent, SendMessage, Broadcast и т.д. Наверное, потому что у меня нажатие кнопок отслеживается в Update, и IDE понимает, что эти дорогие методы вызываются каждый кадр. Тогда переделаю input на новую событийную модель в Юнити, надеюсь получится выжать что-нибудь! Но меня не покидает мысль, что устройство будет "тупить", что я каждый раз вызываю collider.GetComponent - который заново обходит дерево 🌲 компонентов и ищет нужный. Особенно это тупо, когда стреляешь из автоматического оружия с высокой скоростью. Ох, горе мне горе! Надо придумать как это всё закешировать
@@nomadirl3380 Я бы сделал так. У пули есть скрипт, в котором при коллизии она будет проверять есть ли на объекте с которым она столкнулась скрипт противника и если есть, то вызывает в нём метод, который наносит врагу урон.
Примерно так это может выглядеть, если скрипт врага будет называться EnemyDamage, а метод в нём, который будет наносить сам урон - TakeDamage:
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.TryGetComponent(out EnemyDamage enemy))
{
enemy.TakeDamage(damageValue);
}
Destroy(gameObject); // уничтожение пули
}
@@NoobGameDev спасибо за твой пример. В большинстве случаев он решает все проблемы, но я напишу несколько нюансов для тех, кто будет читать эту ветку комментариев:
1) иногда пули (объекты) летят слишком быстро, и при низкой частоте кадров не соприкасаются с коллайдерами - в след. кадре пуля как бы уже за целью, хотя в предыдущем была перед ней
2) иногда дешевле стрелять "лучами", а не пулями (объектами); также у лучей можно указать layerMask - слой объектов, например Damagable, у которых гарантировано будут MyScript, и их коллайдер не придется проверять через if
3) Методы семейства GetComponent - дорогие, потому что каждый раз выполняют поиск нужного компонента среди всех компонентов объекта. Их не стоит использовать в цепочке Update()
@@nomadirl3380 Со 2 и 3-м пунктом полностью согласен) А для решения первого есть простое, но не самое дешёвое (но и не прям уж дорогущее) решение: если на объекте, будь то пуля или противник есть Rigidbody, то можно изменить просчёт коллизий (Collision Detection) с Discrete на Continuous.
Ну, и то, что они пролетаю сквозь коллайдеры не зависит от частоты кадров, так как у FixedUpdate, OnTriggerXXX, OnCollisionXXX, просчёт происходит через фиксированный промежуток времени (0.02 сек. по умолчанию) и не зависит от того насколько быстро обновляются кадры.
Я могу, конечно, где-то ошибаться, но вроде бы так))