Warning: Undefined array key 0 in /var/www/tgoop/function.php on line 65

Warning: Trying to access array offset on value of type null in /var/www/tgoop/function.php on line 65
- Telegram Web
Telegram Web
С одной стороны очень классный доклад - Alexey Merzlikin - Architecture Behind Our Most Popular Unity Games. Cо схемами, преимуществами, недостатками и best practice советами.

Но вот бы прям пример одного контроллера с его кодом, моделями, вьюшкой. Или прям скринкаст модификации их РевардКонтроллера при добавлении нового типа предметов. Какого вообще он у них размера, если нет разбиения по контроллерами предметов каждого типа?

Меня недостаток отсутствия прямой коммуникации между контроллерами сильно отпугивает. Эти неявные связи через модельки совсем не круто. И как-будто бы такая строгость вызвана элегантностью и лаконичностью самой архитектуры - типа дерево же, а не граф - усложнишь, и получится что-то "обыкновенное". А это "обыкновенное" уже не описать за полчаса в виде аккуратного доклада :)

И ещё у меня есть подозрение, что в такой архитектуре велик соблазн некоторые универсальные для многих фичей "контексты" сделать сервисами, т.е. не transient, смешав тем самым слои.

У автора ещё интересный канал есть.

#comment #subscription
Меня постоянно драконит как во всяких подкастах и интервью люди вздыхают о "текущем состоянии индустрии". Особенно по мобильному рынку. Достало. По-моему в мобильных играх просто офигенные тенденции.

Во-первых, отказ от видеорекламы. Практически все новые игры её не используют. Благодаря этому пропадает необходимость ежедневного ретеншена и искусственного раздувания длины сессии. В новых играх прохождение всех дейликов не занимает больше 20 минут. Думаю в будущем многие вообще начнут от них отказываться.

Во-вторых, отказ от продвинутой системы офферов. В "умных" офферах я ничего плохого не вижу, но меня бесили бесконечные всплывашки в прошлых играх и откладывание покупок ради ожидания "выгодных" офферов. Если посмотреть на текущие игры, то там либо вообще нет офферов, либо их всего несколько постоянных. И они не появляются сами, их всегда нужно находить в UI самому. И отказ от офферов не уменьшает fomo, потому что настоящее fomo достигается другими более естественными способами.

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

P.S. Ещё недавно пробовал игру, где мета в портретном режиме, а при переходе на кор ориентация сменяется на ландшафтную. Я такого раньше не видел, и по-моему это тоже огонь.

#everythingelse
Крутой доклад по ECS из alan wake 2. Сначала подробное описание подхода, а потом конкретный пример их фичи с кодом каждой системы. Класс!

P. S. Я никогда не юзал ECS на проде, и для меня мысль, что через ECS системы можно менять просто отдельный ООП стейт нова :) Раньше я как-то думал, что нужно все данные на entity раскладывать и только так работать, но ведь это необязательно, и remedy как раз в примере это показывают.

#comment
Доклад о Monopoly GO! с Unite. У них MVVM с автобайндингом. Но такое ощущение, что их вьюмоделька на самом деле вьюшка (она ведь монобех), моделька - вьюмоделька, а сервис за ней как раз является моделькой. Или может это у меня такой сдвиг, а у них правильная терминология?

Из любопытного у них очень продвинутые байндеры, которые могут, например, перекрашивать text по observable<int> в разные цвета в зависимости от значения. И на слайдах это может показаться крутой фичёй, но их пример выглядит плохо - логика размазывается между вьюмоделью и вьюшкой, в которую зашито магическое число, не поддающееся настройке без изменения вьюшки.

И я не догнал как у них работает байндинг кнопок. В начале говорили, что кнопка напрямую тригерит метод сервиса, что по-моему нарушение всего что можно, а во второй части в коде кнопка тригерит вьюмодельку, которая опять же лезет напрямую в сервис, что уже лучше, но зачем тогда такая generic связь вьюмодельки с моделью, если у неё есть доступ и к сервису.

И в конце самое интересное не рассказали - как они разруливают ситуацию с рандомными наградами? Или в монополии их нет?

#comment
Иногда мне кажется, что я вообще не тем занимаюсь. Вот есть zero sievert, сделанная одним челом и проданная на 300к+ копий по $20. Отзывы в основном положительные (76%). Но в этой игре по-моему нет ничего, кроме прикольной идеи, но криво реализованной абсолютно во всех аспектах. Нет коопа, кривые одноуровневые генерации карт, отвратительный ux, из-за которого даже играть не хочется, отстойные квесты, скучное оружие и враги, никакого лора, графика в конце концов стрёмная. И этому нет никакого оправдания, возможностей у игрока мало и это и близко не "proejct zomboid в виде extraction shooter".

И я не понимаю, почему нет того же самого, но просто более качественного? Почему как на мобилках нету десятков клонов в разных сеттингах? Quasimorph, если что, совсем не то же самое.

#games
Думал V Rising станет первой игрой, где я найду применение задним подкрылкам своего 8BitDo PRO 2 - стану вращать им камеру. Но, увы, макросом это не получилось реализовать.

А вообще, круто было бы скрестить zero sievert и v rising. Строительство базы днём как мета на отдельной локации, и ночные уровни c экстракшеном.

#idea
На конференции мне было прям максимально неуютно - как будто бы большинство участников были студенты или джуны, мечтающие устроиться на работу. Не подошёл ни к одной стойке с шоукейсом. Я прям чувствую как раздражаюсь, когда хотя бы из далека вижу очередной платформер/метроидванию/фпс на ассетах. Но не хочется быть мудаком, который обсирает чужую игру. Была бы юнити открыта с проектом - вот тогда другое дело :)

Из лекций и общения между ними вынес только две вещи - инвестируют только в тех, кто готов заложить квартиру на свой проект. И от этого такие маленькие суммы инвестиций - какие-нибудь 10 миллионов могут сделать погоду только человеку, у которого уже долгов на 50 миллионов. И надеяться на изменение ситуации - наивно, рост геймдева уже лет пять не поспевает за рынком. Это отрезвляет.

#everythingelse
На питч-сессии не был, полистал на записи и не жалею - сгорел бы с кринжа) Невероятно жаль, чтобы не было никого достаточно борзого, кто на вопрос про "непоправимую пользу" от игры ответил бы пожёстче.

Сам бы я хотел делать только максимально вредные игры. Чтобы мне на почту писали родители о том, как их дети вместо уроков в моей игре зависают. Что у людей брак из-за игры разваливается. Что чувак заложил квартиру ради донатов и так и не зароллил персонажа :)

#everythingelse
Дочитал "Шаблоны игрового программирования" Найстрома. Думал будет скукота, но книжка оказалась хорошей. Отличные примеры и немного нутрянки движков, о которой я даже не задумывался, в целом автор скорее рассуждает, а не просто учит. Вообще самое классное в книге не сами шаблоны - а скорее его отхождения от темы - например, описание классов-прототипов JavaScript.

#everythingelse
Действительно прикольная идея делать через статику. В книжке как раз автор размышлял, почему никто не делает синглтоны просто через статические классы. Я когда читал усмехнулся - потому что когда-то тоже задавался этим вопросом и узнал ответ на своём опыте. Попробовал сделать WindowsManagerстатическим. Так вот проблема такого подхода не в том, что их нельзя замокать и передать как зависимость, а в том что если вдруг из синглтона захочется сделать не-синглтон (а это случается чаще, чем кажется), то для обычного Class.Instance достаточно убрать Instance и сделать конструктор публичным. А вот со статическим классом так не получится - придётся переписывать абсолютно весь класс, и это отнюдь не банальное удаление ключевого поля static отовсюду.

Так вот, в этой DI либе показано, что на самом деле сделать из статического класса не единичный экземпляр достаточно просто - достаточно сделать этот статичный класс generic. И тогда можно юзать Class<Id1> и Class<Id2>, а также эмулировать передачу его как параметр через generic методы, хотя это уже полный изврат) но в библиотеке этот подход тоже юзается.

#package
Вышла статья на хабре о собеседованиях на Unity разраба. У меня двоякое впечатление - с одной стороны для аутсорс-компании, занимающейся разработкой прототипов - это выглядит как хороший гайд для просеивания на вакансии джунов и мидлов.

Хотя вот совет 7 насчёт архитектуры - кажется всё-таки сомнительным даже для них. Навыки в архитектуре - это умение упрощать, а не усложнять. И рекомендация не использовать синглтон "потому что его знают все, а создать архитектуру без него умеет не каждый" для меня звучит как "используйте синглтоны - единственную архитектуру, понятную всем". Вообще, использование сложных паттернов мне кажется признаком ранних мидлов, которые только недавно научились всему этому.

Насчёт технических вопросов для оценки знаний. Вот, предположим, кандидат плавает абсолютно в каждой из перечисленных тем - но, парадоксально, у него хороший опыт в резюме. О чем это говорит? Кто-то решит, что соискатель наврал в резюме об опыте, но по-моему нет ничего странного в том, чтобы "быть погруженным" лишь в пару тем из всего этого списка - обычно ведь фичи не на то, как вставить рекламное сдк или настроить мультиплеер, а просто на создание новой функциональности у игры. Для фич не нужно знать ни 2д, ни 3д, ни ui - а знать нужно только уже существующую кодовую базу, при этом она может состоять только из довольно высокоуровневых абстракций. И такому кандидату действительно трудно будет с нуля создавать прототипы, но это ведь довольно специфический скилл, он нужен меньшинству разработчиков, и странно требовать его наличие у всех. Но в тоже время не вижу никакой проблемы для кандидата, имеющего опыт работы в крупной игре, разобраться в перечисленных вещах - всё это просто "знания", которые быстро гуглятся, а для их осознания не нужен практически никакой опыт.

Вопрос "Как ты сделаешь архитектуру движения юнитов для мультиплеерной RTS игры?” - по-моему норм задавать только чуваку, у которого в портфолио есть мультиплеерная ртс. Потому что у него реально должно быть своё мнение на этот счёт, а для всех остальных будет норм ответом (по крайней мере я бы так ответил) - буду гуглить неделю. Ну т.е. я вообще не готов рассуждать прежде чем не ознакомлюсь с темой подробно, потому что не доверяю себе вообще ни в одном вопросе ) Да, я могу накидать способов каких-то, но если я заранее знаю, что правильный способ должен учитывать кучу нюансов, которые мне сейчас даже трудно представить, то лучше ответить "я не знаю". Пообсуждать можно решение какой-то математической проблемы, но к грамотному решению таких технических проблем не придти обсуждением - нужен только опыт - свой или чужой. Так что по-моему ответ "я не знаю" или "я не готов это профессионально обсуждать без подготовки" лучше, чем наивные самоуверенные рассуждения.

Ещё цепануло, что красный флаг в live кодинге это "Ненужные задачи: написание «чистого» кода, рефакторинг, уборка проекта." Для меня читать код не прикасаясь к нему это всё равно что какую-то сложную информацию воспринимать исключительно на слух, не видя перед собой книги. Я всегда что-то переименовываю, где-то перевод строки добавлю, где-то блок в метод вынесу, порядок каких-нибудь методов поменяю... Код практически всегда можно улучшить хоть чуть-чуть, даже свой код закомиченный час назад.

Вот банально код автора из git - начиная реально разбираться в его коде я бы начал с добавления в начало каждого файла #nullable enable и постепенно шёл бы по коду и правил модификаторы, чтобы убедиться что я правильно понимаю как используются переменные, добавлял интерфейсы, чтобы понимать способы использования классов, удалял бы неиспользуемый код...

По-моему обсуждать нужно только опыт кандидата. Как кандидат в своей игре сделал эту фичу? Какие плюсы/минусы их архитектуры? И принимать решение на основе этого обсуждения, а не его опыта, типа "кандидат делал только 3д, а у нас 2д, и у него нет опыта со спайном", или "у нас ECS, а чувак только ООП видел", или "у него синглтоны, а у нас тут DI со стейт-машинами". В конечном счёте важны только желание работать и способность учиться.

#comment #subscription
В новой фиче на работе очень много разных комбинаций анимаций, и решили их делать через асинхронщину. В итоге узнал кучу нового.

Оказывается async во многих случаях необязателен - по сути он нужен лишь когда внутри используется await. Без него стейт-машина под метод не создаётся, а значит отсутствие модификатора async - оптимизация.

Стандартные Task начиная с версии unity 2018.3 возвращаются в основной поток Unity, если вызваны в нём. И запускаются тоже только в основном потоке, за исключением Task.Run (если у вас не webgl, конечно). В точности как UniTask. Так что ради мелких оптимизаций его тянуть в проект не стали.

Awaitable, кстати, тоже всегда работает в одном основном потоке, но в них как я понял нет аналога Awaitable.Run чтобы сравнить (который, впрочем, и не нужен).

#work
Часто встречаю идею дробления проекта на кучу ассемблей, но мне всегда казалось что доводы (ускорение компиляции, лучший контроль зависимостей, теоретическая возможность переиспользования) недостаточны, чтобы перекрыть минусы - собственно рутина создания этих asmdef и прокидывание их друг в друга)

Но сейчас вот разбираю один проектик, где каждый сервис в своей asmdef и там есть один плюс, про который никто не упоминает, и который мне очень понравился - большинство классов можно помечать internal, а не public. Таким образом действительно "детали реализации" не мешаются снаружи.

#everythingelse
Новый канал Netcode's shenanigans от автора massive-ecs. Очень доступно и интересно пишет про неткод - надеюсь на продолжение. И какая всё-таки крутая PoE под капотом: возможность в опциях выбирать систему синхронизации - это ведь очень сложно архитектурно, да?

#subscription
Если бы я создавал язык программирования, то запретил бы единичные переменные. Только коллекции: вместо int x = 5 — ints x = {5}. Потому что самые сложные рефакторинги начинаются, когда одна сущность превращается в несколько. Пусть язык сразу учит думать масштабно.

#everythingelse
[1/2]

Для прототипирования боя в своей рпгшке я использую ModiBuff. У, меня, если что, довольно классический пошаговый бой (аля Honkai: Star Rail) - ряд персонажей игрока, ряд персонажей врага - перекидываются скиллами, перемещений нет и какой-либо аркадности (как в Sea of Stars) тоже нет.

В ModiBuff скиллы задаются через рецепты. Например, задание рецепта простого скилла "Удар" будет выглядеть как-то так:

Add("Hit")
.Effect(new DamageEffect(3), EffectOn.Init);


И когда игрок применял скилл, то я включал анимацию этого скилла, и в конце анимации применял логику скилла через ModiBuff.

Но сейчас я захотел не просто более комплексных скиллов, а более лучшую визуализацию, и с этим возникли проблемы. Представим себе скилл "удар+выстрел": наносится 3 урона - выстреливается прожектайл - и наносится ещё 3 урона когда он прилетает во врага.
Если пофантазировать, то рецепт ModiBuff такого скилла мог бы выглядеть примерно так:

Add("Hit+Shot")
.Effect(new DamageEffect(3), EffectOn.Init)
.Effect(new Projectile("Shot"), EffectOn.Init)
.Effect(new DamageEffect(3), EffectOn.ProjectileLanded);


Но что если мы хотим выпустить два прожектайла? В стиле ModiBuff было бы разбить рецепт на несколько

Add("Shot")
.Effect(new Projectile("Shot"), EffectOn.Init)
.Effect(new DamageEffect(3), EffectOn.ProjectileLanded)

Add("Hit+2Shot")
.Effect(new DamageEffect(3), EffectOn.Init)
.Effect(new EffectApplier("Shot"), EffectOn.Init)
.Effect(new EffectApplier("Shot"), EffectOn.Init)


Ещё ок, но апи с каждым разом всё усложняется и усложняется. Но что, если сделать созданием рецепта обычным методом?

async UniTask Hit2Shot(IUnit source, IUnit target, IVisualContext context)
{
await new DamageEffect(3).Effect(source, target);

await UniTask.WhenAll(
async () =>
{
await context.ShootProjectile("Shot1", source, target);
await new DamageEffect(3).Effect(source, target);
},
async () =>
{
await context.ShootProjectile("Shot2", source, target);
await new DamageEffect(3).Effect(source, target);
}
);
}

И тут с одной стороны кода больше, но с другой стороны - он ведь понятный. Да?

Это лишь пути задания самого скилла, при этом мы подразумеваем, что сам скилл будем применять асинхронно - то есть реально запускать прожектайл, ждать пока он приземлится и дальше продолжать вычисления. Именно так у меня реализовано сейчас - вьюшка полоски хп подписана на ReactiveProperty<int> HP, поэтому хп меняются именно в процессе применения скилла и вьюшка тут же реагирует цифрами урона. Прожектайл в конце своего полёта уведомляет модельку о том, что он приземлился и триггерит дальнейшие вычисления.

#devlog
[2/2]

Но можно полностью отделить вьюху от логики - сделать так, чтобы скилл применялся мгновенно, но результатом своего применения выдавал набор анимаций. К примеру для
"Hit+Shot" результатом применения было бы

Add("Hit+Shot") 
.Effect(new DamageEffect(3), EffectOn.Init)
.Effect(new Projectile("Shot"), EffectOn.Init)
.Effect(new DamageEffect(3), EffectOn.ProjectileLanded);

var animationSteps = Execute("Hit+Shot", target, source);
/*animationStepa: {
new ApplyDamage(3, target),
new ShowDamage(3, target),
new ShootProjectile("Shot", target, source),
new WaitForSeconds(1f),
new ApplyDamage(3, target),
new ShowDamage(3, target)
}*/


Это был простой случай применения скилла. А теперь представим, что на нашей цели висит щит, отражающий атаки. Тогда результатом должно быть что-то вроде такого:

/*animationSteps: { 
new ShowShield(target),
new ShootProjectile("Shot", target, source),
new WaitForSeconds(0.2f),
new ApplyDamage(3, source),
new ShowDamage(3, source),
new WaitForSeconds(0.8f),
new ShowShield(target),
new WaitForSeconds(0.2f),
new ApplyDamage(3, source),
new ShowDamage(3, source),
}*/


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

Вообщем я для простоты пока что запилил через асинки без рецептов ModiBuff (но с его контроллерами) - и сосредоточился на других вещах. Но меня не покидает ощущение, что я упускаю какое-то простое и элегантное решение...

#devlog
2025/01/06 15:49:37
Back to Top
HTML Embed Code: