Telegram Web
Ameba
#лайт
Достала меня ситуация с кучей мессенджеров. Психанул и начал писать свой единый клиент. Называется Aggregate Message Bar, сокращённо Ameba.

Да, всяких приложений, объединяющих мессенджеры, как грязи. Я какое-то время использовал врапперы вэб-версий (Franz, Rambox), смотрел мультиклиенты (Pidgin), интеграции ботами (Sameroom), ещё какие-то сервисы и протоколы. Но это всё не то и не так. Как говорится, если хочешь сделать что-то без фатальных недостатков — сделай это сам.

Амёба разрабатывается прежде всего под Android, но будет также работать на десктопах (Windows, Linux, OS X). С айфонами гемороиться лишний раз мне не охота, но при очень большом желании можно будет запихать и туда, так как создаётся приложение на Qt.

Программа минимум — поддержать API Telegram и Slack. Если попрёт, то можно будет добавить Twitter, Discord. Может быть что-то ещё. Для начала ограничимся текстом с базовым форматированием, блоками кода, картинками, ссылками. Но сверху на это накрутим группировку каналов и подобные плюхи. Схему аккаунтов и группировку чатов планирую сохранять и синхронизировать через AWS AppSync. Опционально можно будет хранить там же и пароли.

Ориентир в плане юзабилити для меня — это телеграм. Но в Qt, к сожалению, нет стандартного контрола для редактирования текста, вменяемого работающего на мобилках; поэтому придётся все тачи и драги над текстом обрабатывать самому. На данный момент именно этим занят. Следить за разработкой и ставить звёзды можно на github (это open source):
https://github.com/Alprog/Ameba

И да, если вы находите текущий логотип уродливым, но готовы нарисовать и подарить мне более красивый — я весь внимание.
Ещё одна история о том, как попасть в профессию (как будто таких мало)
#лайт
Сегодня мне исполняется 29 лет со дня рождения и ровно 9 лет, как я официально работаю в индустрии. Это повод для меня вспомнить, как это было, и написать свою версию ответа на один из вечных вопросов новичков: как же разорвать замкнутый круг, когда для трудоустройства требуется опыт, а для получения опыта требуется трудоустройство?

Итак, осень 2008 года. Мне 19, я студент третьего курса, который только что закончил маленькую тактическую RPG на Visual Basic 6.0 (её скриншот вынесен в заголовок поста), которую пару лет делал по вечерам с командой, собранной в интернете. Проект так и назывался: «Маленькое и Скромное РПГ», так как создавался исключительно по фану и состоял почти полностью из говнокода. На этом мой опыт по большому счёту заканчивался. Контора, в которой я хотел работать, переехала в другой город, а в единственной оставшейся студии видеоигр требовались только флэшеры.

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

Там мне сказали, что это всё замечательно, но сейчас проектов нет (вакансия к этому моменту действительно уже пропала с сайта), но есть планы делать в будущем большой флэш проект (забегая вперёд скажу, что когда я оценил обстановку изнутри компании, стало понятно, что дальше разговоров этот проект и не мог пойти). Ещё сказали, что им нужен человек на фултайм, а я студент. И ещё что нет опыта, но если что, то мне позвонят. Я взял визитку и ушёл в дождь. В тот день было ясно, но для драматизма ситуации скажу, что ушёл в дождь.

В июне, как только сдал сессию, я написал им снова. Мол, летом я свободен на весь день. На этот раз мне не ответили. Я написал ещё раз и опять тишина. Тогда я достал визитку директора и тупо позвонил ему на личный мобильник. Мне сказали, что вообще не ищут сейчас новых сотрудников и тогда я предложил взять меня «на практику от универа», что означало поработать за чай и печеньки. И меня взяли. А через месяц, в мой двадцатый день рождения, предложили принять меня в штат. И я даже не сразу согласился на начальные условия, а поторговался.

Вот, собственно, и весь секрет. Даже если нет нигде вакансий, требуется немного напористости и готовность 1-2 месяца поработать за очень мало или за печеньки — и вот у вас уже есть опыт. Замкнутый круг разорван, вы теперь востребованный джун, и с вами уже совсем по-другому разговаривают. А дальше — больше.
Мудрость про таск-трекеры
#лайт
Знаете, что самое важное в трекере задач? Инструменты отчётности? Уведомления? Может быть, интеграция с системой контроля версий? Не, это всё фигня. Самое важное — это количество кликов при работе с ним.

Вы можете что угодно думать по поводу того, что пара лишних кликов ничего не меняют; но когда вам нужно указать тип задачи, компонент, теги и сроки, чтобы тупо создать задачу, вы просто не будете этого делать. Создать задачу должно быть также легко, как записать её в блокнот. Также быстро, как сказать её соседу. Если для создания задачи «выровнять логотип по центру экрана» требуется сильно больше действий, чем просто ввести этот текст, то вы обязательно рано или поздно поленитесь это сделать. Или напишите это в чат напрямую ответственному, воруя время у себя, у него, и ещё рискуя потерять эту задачу в будущем.

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

У нас тогда был собственный багтрекер, до сих пор недостижимый идеал в плане количества кликов при работе с ним. Я не рекомендую вам писать своё, но советую повозиться с настройками вашего трекера. Тратя время на то, чтобы сократить один клик, вы в конечном итоге экономите человеконедели.
Мам, на меня смотрят тёлки
#лайт
Выступал вчера с докладом на местом геймдев-митапе. Рассказывал, каково это быть техдиром на удалёнке. Записей никаких нет, но есть мнение, что я топ-докладчик. У меня это уже третий опыт подобных выступлений и с каждым разом заходит лучше и лучше. Я изначально довольно скептически отношусь к полезности 99% докладов на конференциях (включая свои), поэтому упор делаю на подачу: пусть людям будет хотя бы интересно это слушать. Нет, толика смысловой нагрузки, конечно, в моих докладах имеется, но я всё приправляю шуточками и смешными слайдами. Шутки при этом стараюсь встраивать нативно в рассказ, а слайдами играю в основном на неожиданности. И ещё громкими тезисами кидаюсь, чтобы не засыпал народ. Думаю, у меня хорошо получается чувствовать аудиторию. Правда, речь хромает: всё ещё много экаю.

Ну а ещё по фоткам я наконец-то увидел, как растолстела моя ряха за последние полгода. Надо завязывать с доставками еды и налягать на баскетбол.
Девлог #0
#лайт
Начали снимать дневники разработки по Encased. В этом выпуске общая информация про игру, а также рассказываем о работе с комьюнити. Ребята на видео как-то подозрительно много улыбаются. Наверное, потому что меня пока нет в офисе. Ну, ничего — в августе навещу их снова!

https://www.youtube.com/watch?v=z5lMainBskQ
Сумбурная объяснялка про тайлики и рамочки
#код
Обещался побольше рассказывать про код Encased, а не пишу совсем. Нехорошо. Будем исправляться. Сегодня незначительная, но довольно замороченная тема: как рисуется у нас рамка для зон досягаемости под ногами персонажа.

Начать придётся с конца. Ходят персонажи у нас не по 2D-пространству, а по сложному 3D ландшафту со всякими ямочками, холмиками, мостиками через канаву и вторыми этажами. А потому игровая сетка — штука сложная: не массив, а самый настоящий граф. В большинстве случаев одна игровая клеточка это ровно один квад, но иногда, на всяких неровных поверхностях, это 16 квадиков помельче (4x4). Так или иначе, вертексы этих квадиков имеют две текстурные координаты. Одна хранит локальные координаты внутри клетки, другая же — индекс клетки. Ну просто порядковый номер клетки (интовый), так как граф может иметь самую разнообразную форму и 2D-координаты на него не натянешь.

Ещё есть специальная текстура, которая динамически меняется во время игры и где каждый тексель (по порядковому номеру) указывает шейдеру на то, какой спрайт нужно выводить в этой клетке. У текселя 4 компоненты RGBA, которые прекрасно кодируют Rect спрайта внутри атласа. Более того, как несложно заметить, переставив каналы местами, мы бесплатно получаем ещё и любые зеркальные отражения спрайтов.

Осталось эти спрайты нагенерить. Но не рисовать же все варианты спрайта, правда же? Поэтому делим спрайт на 4 части и рисуем варианты только для левого-верхнего уголочка. У меня получилось 5 видов: пустой, горизонтальная грань, вертикальная грань, обе грани, уголочек (см. рисунок). Это кодируется тремя битами. Кусочков 4, так что полностью спрайт определяется 12-битным числом. Если оставить только возможные комбинации, то их 625 (5^4). Пробегаемся по этим вариантам, проверяем их на валидность (биты горизонтальной и вертикальной линии у соседних кусочков должны совпадать) и генерим спрайты. Попутно, разумеется, чекаем их на зеркальность и составляем мапу (12-битное число -> 12-битное число + вид зеркального отображения). И получается всего навсего 20 уникальных спрайтов.

Далее зашиваем это всё в атлас вместе со всякими другими спрайтами для других режимов отображения (само собой, своей собственной зашивалкой). Ну и потом в игре вычисляем зону досягаемости, смотрим на соседей каждой клетки и составляем для неё 12-битный индекс, лезем в мапу, достаём оттуда другой индекс и режим отображения, из данных атласа получаем соответствующий рект, пишем это дело в нужный тексель текстуры, а в шейдере читаем и рисуем на нужном месте. Готово.

Если вы уследили за моей мыслью, держите пятюню. Если в какой-то момент поплыли — буду рад фидбеку, где именно я пишу непонятно. А если я у вас отбил всякое желание стать графическим программистом, то я не специально.
Феерическая расстановка точек над Unity
#лайт
На прошлых выходных занесло меня на re:indiehive в Минске. Это такое сборище инди-разработчиков на веранде бара, где каждый может подойти к микрофону и показать на большом экране свой замечательный шедевр. В конце организаторы устроили круглый стол «Что выбрать: Unreal, Unity или Defold?»; и кто знаком со мной лично, тот уже знает, с какими примерно речами я туда влез. А вот большинство читателей моего канала об этом ещё не слышали, а потому я надумал наконец внятно сформулировать свою теорию в виде поста.

Если коротко: Unity — зло, нанесшее непоправимый урон индустрии и уничтожившее целое поколение программистов. Если же мысль разворачивать, то мой хейт этого движка имеет две основных составляющих: техническую и идеологическую. О технических проблемах сказано уже немало слов, да и с появлением таких вещей, как ECS и ScriptableRenderPipeline, ситуация последнее время стала улучшаться. Поэтому я остановлюсь на второй и основной претензии — идеологической.

Зададимся вопросом: почему бизнес выбирает Unity? Не потому что на нём удобно разрабатывать, не потому, что он имеет какие-то технические преимущества; бизнес выбирает Unity в первую очередь из-за того, что у него огромное количество успешных шоукейсов, а на рынке полно специалистов: их легко найти и в случае чего безболезненно заменить. С точки зрения ведения бизнеса, это идеально. Да и разработчикам, в принципе, неплохо: достаточно изучить один простой движок и ты уже востребованный специалист. Больше разработчиков Unity — больше вакансий. Больше вакансий — больше разработчиков. Ком растёт и в какой-то момент превращается в чёрную дыру, из которой уже ничего не возвращается.

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

— А что, собственно, плохого в том, чтобы знать только Unity? — спросите вы.

Просто посмотрите, какие требования к программистам были в индустрии 10 лет назад. Достаточно пробежаться глазами по вопросам знаменитой статьи Бориса Баткина «интервью глазами пострадавшего» и убедиться, что мы бы не ответили и на половину. И сравнить это с сегодняшним днём, когда на собеседования приходят так называемые Unity-программисты с опытом разработки 3D игр более двух лет и неспособные ответить на вопрос «Что такое Depth Buffer?»

И ведь нельзя сказать, что люди стали тупее. Им просто негде стало расти. Кругом только мобильные проекты на Unity. И соответствующего уровня разработчики. Открой сейчас крутейший офис в Москве и дай денег на разработку Uncharted 5, нанять будет некого. У нас не наберётся столько спецов такого уровня. И дальше будет только хуже, петля затягивается.

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

Хотел бы я сказать, что мы в Dark Crystal Games поступаем более ответственно, но, увы, наша первая игра тоже на Unity; и не факт, что мы сможем соскочить с этой иглы. Особенно, если следующий проект будет похож на нынешний.

Верю ли я в то, что ситуация в российском геймдеве когда-нибудь изменится? Да. Знаю ли я, как это сделать? Нет.
Счастливый отзыв о серебряной пуле в мире VCS
#лайт
Не пытайтесь вспомнить другую расшифровку аббревиатуры VCS, речь в этой заметке действительно пойдёт о системах контроля версий. Казалось бы, ну сколько можно уже? Вроде бы программисты всего мира давно уже определились и решили, что для распределённой разработки ничего лучше git’а не существует. Есть, правда, горстка староверов, которые по собственной воле продолжают истязать себя SVN, но, надеюсь, среди моих читателей таких немного (фу такими быть). В наше время всё же большинство пилит софт в git’е и горя не знает. Везде, кроме геймдева. Потому что у нас, помимо непосредственно девелоперов, есть ещё артисты. И с ними вечно какие-то проблемы. Как говорится, курица не птица, артист — не разработчик.

Проблемы с художниками две. Во-первых, их тонкая душевная организация плохо сочетается с философией git’а. Будем честны, не каждый программист в неё вникает сразу, чего уж ждать от людей творческих. Справляются с этой проблемой в разных студиях по-разному: кто-то заводит для артистов отдельный SVN репозиторий; кто-то вставляет за ними графику руками; есть даже те, кто утверждает, что ценой невероятных усилий умудряется обучать гиту своих художников (до конца не верю!); кому-то боль облегчает git-flow; но в той или иной степени, страдают все.

Вторая проблема с артистами заключается в том, что они имеют обыкновение коммитить бинарный арт килотоннами, и на том же bitbucket’е место заканчивается мгновенно, а решения типа LFS помогают слабо, т.к. требуют соединения с сервером и убивают этим всю суть распределённой системы (по ревизиям уже просто так не попрыгаешь локально).

И вот обе эти проблемы, как по волшебству, решает PlasticSCM. Это VCS, созданная специально для нужд геймдева. У неё есть два режима работы. Первый как в git: у вас есть рабочая копия репозитория со всей историей, вы можете локально делать ветки, мержи, стэши и всё остальное, к чему привыкли. И второй режим для артистов: всё то же самое, но репозиторий храниться не у вас, а в облаке. То есть у вас commit всегда сопряжён вместе с push, а update с pull’ом. Это уже само по себе отсекает половину ситуаций, вызывающих сложности. Но плюс к этому, в пластике ветки являются не легковесными метками, а полноценными объектами. Каждый changeset (ревизия по здешнему) жёстко привязан к какой-то конкретной ветке. Другими словами, объекты, которыми оперирует пользователь, точно отражают термины, в которых он думает (по крайней мере, если вы работаете по схеме git-flow). В такой системе гораздо ниже вероятность совершить ошибку. Здесь в принципе не может возникнуть ситуации, вроде оторванной головы, которую сложно решить, не понимая низкий уровень. И как показывает практика, контевики тут вполне осваиваются и справляются даже с ветками.

Есть ещё в пластике третий режим. Это отдельный клиент, где нет веток вообще, а пользователь всегда сидит на последней ревизии main’а. Но этот режим совсем для слабаков и мы его не используем. Также есть ещё lock-и файлов, как в Perforce, но Unity плевать хотело на readonly флаги, поэтому ими мы тоже не пользуемся.

Что касается проблемы с большими файлами, то примерно за те же деньги, что на Bitbucket дают 100 GiB LFS, в PlasticSCM дают 100 GiB основного репозитория. Да, рабочие копии у программистов пухнут, но это меньшее из зол. Обрезать историю, к сожалению, возможности нет, но можно выкачивать отдельные ветки. То есть, если будет совсем невмоготу, в качестве костыля всегда можно сделать бранч от начала проекта и залить туда текущий слепок проекта.

Мы работаем с пластиком уже 5 месяцев и очень довольны. Но для своих личных проектов, я, понятное дело, всё равно буду использовать git. Впрочем, ещё до того, как я узнал о существовании PlasticSCM, я начинал делать клиент для git, реализующий похожие идеи в интерфейсе по упрощению работы с ветками. Называться он должен был GitTern. Может быть, ещё вернусь к нему, когда загруз по работе пройдёт. Но это уже совсем другая история.
Развлекалочка для программистов
#кодище
Последняя запись на канале заканчивалась тем, что у нас загруз на работе; поэтому я и пропадал так долго. Но вот мы наконец-то залили в последнюю минуту билд, его сейчас показывают всяким разным игрожурам в Сан-Франциско, а я могу вздохнуть свободно и оглядеться по сторонам. Писать обстоятельный пост про какую-нибудь нашу подсистему у меня сейчас нет никаких сил, поэтому развлеку вас пока небольшой приколюхой для программистов.

Думаю, после нормальной сишечки каждого ужасно бесит, что в шарпе нельзя ссылочные типы проверять на null простым условием:
if (refObject)

а приходится писать
if (refObject != null)


Классическое решение — неявный оператор каста в bool. Я вот почти все свои классики наследую от Boolable:
public class Boolable 
{
public static implicit operator bool(Boolable ref)
{
return ref != null;
}
}


Догадываетесь, что может пойти не так? А кейс на самом деле достаточно интересный. Вот есть у вас два класса, наследуемых от Boolable: A и B, и вам надо в каком-то месте проверить равенство объектов:
if (foo1.objectA == foo2.objectA)

но вы маленько опечатались и сравнили объекты разных типов:
if (foo1.objectA == foo2.objectB)


Не смотря на то, что мы передаём разные объекты, условие будет всегда срабатывать, если объекты Boolable. Счастливой отладки, как говорится :)
Пиарчик симпатичного канала
#код
Нравятся вам мои лонгриды с пометкой #код? Если да, то вам стоит также глянуть канал @gamedev_architecture. Это, пожалуй, самый близкий ко мне по контенту канал из тех, что я знаю. Автор тоже фокусируется на всяких интересных решениях в геймдеве с точки зрения программиста, но делает это не в виде фронтовых писем и баек, а оформляет в большие обстоятельные статьи по конкретной проблеме. Технические статьи, признаться, я у него не всегда осиливаю, но философские опусы мне, как правило, заходят. В частности, про командную работу замечательную колонку от 15 мая рекомендую к прочтению людям как с опытом, так и без.
Позитовый петух или новый формат вещественных чисел
#кодище
Как говорится, никто не умеет пользоваться числами с плавающей точкой. Одни люди недооценивают опасности, которые они в себе таят; другие, напротив, боятся слишком сильно и делают много лишних проверок. Реальное же положение дел где-то посередине. Нюансов работы с ними так много, что порой хочется обобщить одной фразой. В определённых кругах достаточно сказать «плавающий петух», многозначительно вздохнуть, и все всё поймут.

И вот, когда мы, казалось бы, привыкли к одному, в птичнике появился новый обитатель. Таинственный, непонятный. Позитовый петух. Речь идёт про так называемые posit’ы. Формат вещественных чисел, который придумал в прошлом году Джон Густафсон, и который в теории будет сильно круче обычных флоатов, если реализовать его в железе.

Я постараюсь сейчас дать краткий обзор формата и объяснить, почему он крутой. Чтобы что-то понять, вы должны уже иметь общее представление о бинарном устройстве обычных флоатов (если вы такими вещами никогда не интересовались, то вам стоит пропускать пока мои посты с пометкой #кодище).

Итак, позиты задаются двумя числами: n = общее количество бит в переменной, и es = количество бит, отведённых на фиксированную часть экспоненты (об этом позже). Также как и во флоатах, в позитах сначала идёт бит знака, затем экспонента и в конце мантисса. Но экспонента здесь имеет переменную длину. Соответственно при различных значениях экспоненты будет оставаться разное количество бит под мантиссу. То есть максимальная точность будет меняться в зависимости от значения экспоненты.

Экспонента имеет разную длину, потому что она записывается в особом формате. Выделяется фиксированное число (то самое, заданное по условию) младших бит экспоненты, которые остаются без изменений. Но старшие лидирующие биты называются «режим», и записываются с помощью run-length encoding. Понять принцип можно из таблички:

1111   8    1111   3 
1110 7 1110 2
1101 6 110. 1
1100 5 110. 1
1011 4 10.. 0
1010 3 10.. 0
1001 2 10.. 0
1000 1 10.. 0
0111 0 01.. -1
0110 -1 01.. -1
0101 -2 01.. -1
0100 -3 01.. -1
0011 -4 001. -2
0010 -5 001. -2
0001 -6 0001 -3
0000 -6 0000 -4

Две левые колонки это бинарное представление бит экспоненты флоатов и их значение. Две правые — то же самое для режима позитов, где символ «.» означает «не имеет значения».

Из таблицы понятно, что серия из n повторяющихся единиц до первого нуля означают n - 1; а серия из m нулей, означает -m. Если серия закончилась раньше обычного, то фиксированная часть экспоненты тоже сместится влево. А следом за ней и мантисса, благодаря чему она получит дополнительные биты точности. Если же серия закончилась позже обычного, то она, напротив, отожрёт биты у мантиссы. Более того, если и этого не хватит, серия начнёт отнимать младшие биты экспоненты. Вплоть до полного заполнения всей ширины числа (младшие биты экспоненты, которые не влезли считаются равными нулю).

Легко увидеть, что точность добавляется у чисел близких к единице и теряется у очень больших значений. Что обычно и требуется на практике. Более того, благодаря возможности заполнить всю ширину числа одним только режимом, позиты начинают хранить значения очень близкие к 0 без хаков с денормализованной формой (два -6 в табличке выше у флоатов — это не опечатка).

Также позиты не содержат кучи NaN’ов и прочей ерунды. Из особых значений есть только 0 и ±∞. Причём в отличие от флоатов, нет отрицательного или положительного нуля. И бесконечность тоже одна, которая за одно ещё и NaN’ом служит в случае чего. Идея в том, что на практике не нужно всего этого зоопарка, а ошибку надо ловить сразу, с чем я совершенно согласен.

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

Ну разве не восхитительно?

Фух, еле уложился в 4000 знаков. Полную инфу читайте здесь:
https://posithub.org/docs/BeatingFloatingPoint.pdf
2025/07/10 15:46:57
Back to Top
HTML Embed Code: