Серёга Антонов
78 subscribers
29 photos
41 videos
60 links
Всем привет!

Меня зовут Серёга Антонов. Программирую игры и движки. Рассказываю об играх простым языком.

ВКонтакте https://vk.com/antonovcoder

YouTube https://www.youtube.com/@antonovcoder

Написать лично @bestsuperman
Download Telegram
Внезапно туман в Великом Новгороде )
Немного про софтскилы.

Если вам кто то говорит:
- Не хочу тебя обидеть

Значит он будет вас прямо сейчас обижать.

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

Говорить кому то, что он сделал ошибку, пропустил что то, всегда тяжело для обоих сторон. Можно либо сильно обидеть человека, либо даже получить серьезный отпор, или начать спорить до потери пульса. А ошибки то мы все совершаем, всегда. Это неизбежно.

Я прошел довольно большой путь и всякое было. Признаюсь, по молодости, во многих случаях я был не прав. Потом у меня появился наставник Владимир. И мы с ним проработали много лет. Он меня научил, что если работаешь вместе над чем то, и есть какая то цель. То цель превыше всего. Главное достичь этой цели в вашем деле. Все остальное вторично. И когда вы держите цель в голове, все работают на одной волне. Все гребут в одной лодке и в одну сторону.

Вместо фраз в начале этого поста можно же сказать так:
- Слушай я изучил вот это и увидел проблему, давай вместе посмотрим?
- Смотри я вот тут вижу место где можно улучшить, ты пробовал так?
- Смотри я нашел баг, давай вместе чинить!

Собственно тут мы говорим о предмете работы. Всегда держа в голове общую цель.

Всем благ!
Новый видос с демкой в лабе )

ВК
👍1
Forwarded from Лаборатория сборки (Сергей Антонов)
Media is too big
VIEW IN TELEGRAM
Всем привет! Продолжаю делать синхронизацию на базе детерминизма. Про это я подробно рассказывал здесь. В данном видео я показываю синхронизацию более сложной стркутуры данных. Она описывает два экрана, между которыми можно переключаться. На первом экране у нас небольшая физическая симуляция и обработка столкновений. На втором экране можно редактировать текст одновременно. Данный подход синхронизации организует строго последовательный поток событий или как я называю изменений от пользователей. Этот поток синхронизируется между всеми узлами, тем самым позволяя нам расчитать точную сцену в любой момент. Кроме того в данном подходе свои изменения применяются сразу, тем самым пользователь никогда не увидит лага от своих действий. Синхронизацию текста я сделал на базе строки и позиций курсоров, которые взял из уже готового нашего контрола. Я вычисляю дифф текста и преобразую его в одну из операций - удаление или вставка. Так же есть операция перемещения курсора. Эти операции применяются последовательно на каждом клиенте. И дают идентичный результат. Более подробно в видео.
🔥2
Всем доброго утра! 😀

Синхронизация текста завела меня в дебри андроида. Начал я тестить одновременный ввод. С компа и с телефона. Если медленно делать ввод с обоих девайсов, то все прекрасно. А если быстро вводить, то тут по какой то причине курсор компа стал прыгать в сторону курсора андроида. Начал дебажить, выяснил, что проблема где то в вводе из софт клавиатуры. Начал более детально смотреть...

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

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

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

Так вот проблема в том, что установка и чтение асинхронны. Клавиатура очевидно работает не в нашем потоке, она как отдельная программа. При установке мы шлем ей наше состояние. Она его применяет у себя, потом обрабатывает ввод пользователя и отправляет нам результат. А мы его получаем по событию. То есть асинхронно. Причем если бы событие приходило именно на изменения пользователя, то все было бы корректно. Но проблема в том, что клавиатура присылает изменения и на нашу установку текста. И получается я отправил текст, а мне спустя кадр-два прилетает обновление, а я не знаю, это то что я отправил или это пользователь ввел? Вот к чему приводит асинхронность и плохой дизайн интерфейса.

В общем буду думать как это обойти...
👍2
Когда программист пишет новый проект, по началу это всегда легко, просто и явно. Со временем кодовая база проекта растет и становится сложной в понимании. А это понимание необходимо для дальнейшего изменения проекта. В итоге проект превращается в такую сложную логическую машину, что любые изменения могу провести к неожиданным результатам. Мало того растут неявные связи и пути этой логики. Это абсолютно неизбежно.

Мы программисты программируем логику. По сути мы перекладываем эту логику в код. А что бы нам добавить еще немного логики, нам надо сначала прочитать эту логику из кода и осознать ее. Затем поменять ее в голове и только после этого дописать код. Поэтому видеть явные взаимосвязи логики в коде это очень важно - наглядность всегда упрощает понимание. Не все языки программирования и архитектуры нам в этом помогают. Да и во всем есть свои плюсы и минусы. Достичь явность логики в коде это прямо серьезное испытание.

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

Продолжение в следующем посте.
В предыдущем посте я рассуждал о явности и сложности кода.

Теперь давайте посмотрим какой инструментарий мы имеем сегодня?
Посмотрим в со стороны явности.

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

События
События вызывают непонимание последовательности их выполнения. От этого очень сильно страдает явность. К тому же надо следить за удалением подписки на события. Дебаг событий превращается в ад )

Зависимости
Зависеть от чего либо это само по себе очень плохо. По сути страдает суверенитет вашего программного продукта. Чем больше зависимостей тем хуже. На практике ты тупо зависишь от того как чужой Вася написал код в своей либе. И тебе придется буквально адаптировать свой код под Васю.

Версионирование
Любое изменение любой библиотеки может сломать вашу программу. Вот прямо даже если 1 бит поменялся. Предполагается, что патч-минор версии служат исправлению багов и добавлению фич. Но где грань? Кто определяет, что это патч или минор? Это все ненадежно, проверено на практике многократно.

Entity component system (ECS)
Это когда у нас есть абстрактная сущность и мы можем вешать на нее любые компоненты. А так же есть системы-функции которые постоянно обрабатывают эти компоненты по отдельности либо по типам группами. Супер гибко! Но тут проблема в том, что сущности и связанные с ними компоненты создаются во время исполнения и проследить явную связь в коде невозможно. Ты как детектив будешь на доске выстраивать взаимосвязи компонентов и сущностей. Этот принцип возможно подойдет только для чувствительных к производительности систем, но явности он точно не добавляет.

Тесты
В теории сначала пишем тесты, а потом код к ним. Звучит просто, но практически всегда системы бывают на столько сложными, что ты не знаешь, что тестировать. Сначала надо написать не один прототип, что бы понять, что в итоге. Поэтому тесты хороши для сохранения устоявшихся решений и логики. Они позволяют быстро проверить не сломалось ли чего после твоего изменения. В общем тесты добавляют явность и еще служат примерами использования.

Data-driven
Это когда данные являются главными. Так же данные являются и интерфейсом для общения библиотек. Код в данном случае просто постоянно изменяет эти данные. Так как данные мы описываем четкими структурами то можно проследить где конкретное свойство используется. Так же мы можем код разбить на четкие небольшие процедуры которые берут часть данных меняют их и кладут в другую часть данных - мы явно можем увидеть это в коде. Процедуры общаются через данные. Это однозначно прибавляет явности.

В следующем посте подведу итог и расскажу к каким выводам мы пришли в Точке Сборки.
👍1
Media is too big
VIEW IN TELEGRAM
Ранее я рассказывал про проблему синхронизации одновременного ввода текста.

В итоге проблему удалось решить комбинировано. 

- Во первых добавил историю установки значения. Она убирает ивенты от наших изменений и старые значения не всплывают.
- Во вторых сузил контекст. Я передаю в Ime State все, что попало в текущее выделение в том числе текущее слово.

Более подробно показываю в видео.

ВК
👍1
В продолжение предыдущего поста.

Я писал много приложений разного типа, на основных платформах и популярных языках программирования. В основном они были написаны в ООП стиле со всеми рекомендациями из учебников. Как я говорил в прошлом посте, ясности в понимании этого кода не было. Была сильная связанность и запутанность кода, необходимо было много времени и документация, что бы понимать как примерно работает код.

В свободное время я экспериментировал со своими игровыми движками, и прощупывал разные архитектуры и подходы. Я хотел убрать сильную связанность кода между модулями, и что бы например я мог менять рендер в любое время. Например это могла быть обычная и дебажная отрисовка, или даже без отрисовки можно было бы запустить тесты без инициализации рендер системы. Мне нужно было абстрактное описание сцены, что бы оно не тянуло ничего и было самодостаточным. И несколько рендеров, что бы они смотрели на сцену и рисовали по своим принципам. Например если бы мы делали шахматы, то можно было бы сделать классический 2д рендер, а можно нарисовать реалистично в 3д с тенями, отражениями и бликами, а можно отрисовать в пиксель-арте. Это мы говорим про output, но по сути тоже самое с input. То есть все события мыши, клавиатуры и т.д. тоже хотелось бы основательно отделить. Получется у нас есть модель сцены в виде четких законченных структур, которые описывают сцену полностью и достаточно. Вы можете предложить, что все легко делается с помощью внедрения зависимостей (dependency injection). Именно так я и сделал в своем последнем движке. Но там проблема в том, что придется юзать интерфейсы, а значит об этих интерфейсах должны знать все части и модель и рендеры. К тому же интерфейсы закладывают ограничение или наоборот излишек. Мы же хотим, что бы наша модель не имела зависимостей. И тут нам приходит на помощь такая концепция как data-driven.

Далее исторически я присоединился к Точке Сборки, где задолго до этого Антон Волков разработал Дата-подход. И мы с коллегами используем его во всех программах.

В итоге, что мы имеем:
- Данные главные. Все общение систем происходит через данные.
- Мы описываем нашу модель понятными и легко читаемыми структурами данных.
- Что бы менять данные, нам нужны процедуры. В нашем понимании процедура это функция которая принимает данные и меняет их.
- Список процедур, которые меняют наши данные, мы называем - процессом.
- Процедуры могут быть вложенные друг в друга.
- Мы можем убирать или добавлять любую процедуру.
- Добавляя новую процедуру сложность кода растет линейно.
🔥6👍2
Немного пофилософствую.

Сейчас в сети много видосов сгенеренных нейронками. Все они конечно угарные, некоторые даже поражают воображение. Недавно я поймал себя на мысли, эти нейро-видосы (а так же и тексты) очень похоже на сны. Как будто тебе это снится. Оно как бы выглядит в начале реалистичным, а потом присматриваешься и понимаешь, что оно ненастоящее. И когда ты распознаешь это, то как будто испытываешь облегчение - фух это всего лишь сон.

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

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

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

Я отношусь к нейронке как к умной базе данных. Новый гугл который умеет найти то, что мне надо. Притом, что то стандартное. Если начать задавать нестандартные вопросы - получишь бред - то чего не существует - сон.

Хороших снов!
🔥31
Media is too big
VIEW IN TELEGRAM
Посмотрел недавно ролик GTA VI и нахлынула ностальгия. Захотелось поиграть в культовую GTA III, с той которая на мой взгляд и положила начало игр с открытым миром. Немного разобравшись, что как устанавливать, нашел несколько версий игры. В том числе с переводом. Оказалось, что у GTA III есть сообщество, которое пилит моды и даже озвучивает игру.

Оригинальная игра вышла в 2001 году для PS2 британской студией британской DMA Design (потом стала Rockstar North). Издана американской студией Rockstar Games. Потом в 2002 году вышла на PC и в 2003 на XBox. Команда разработчиков состояла примерно из 23 человек. В игре использовался движок RenderWare.

В последние годы стало модно делать ремастеры популярных старых игр. Так появился ремастер-сборник аж трех игр "Grand Theft Auto: The Trilogy - The Definitive Edition". В него вошли GTA III, Vice City и San Andreas. Ремастером занималась студия Grove Street Games. Выход сборника на всех популярных платформах состоялся в 2021 году. Для рендера взяли Unreal Engine 4, а физику сохранили. Так же улучшили все модели, а для улучшения текстур использовали нейронки.

В этом видео я не только играю в эту культовую игру, но и сравниваю ее с новой версией Definitive Edition.

00:00 - Вступление
00:37 - Заставка
01:23 - Меню
02:18 - Стартовая кат сцена
04:25 - Едем на тачке домой
05:40 - Приехали в дом
05:52 - Сравниваем гаражи
06:03 - Едем на первую миссию
06:24 - Приехали в клуб Луиджи
07:22 - Едем за Мисти
08:39 - Успешно выполнили миссию
08:57 - Сравниваем заход в гараж
09:10 - Сравниваем графоний
11:05 - Едем в загородный дом мафиози
11:56 - Сравниваем графоний там
12:54 - Немного про звук движка
13:16 - Физику оставили ту же самую
13:37 - Вид сверху как отсылка к старым играм
14:12 - Наводим суету
16:25 - Лайфхак как повысить жизни
17:26 - Немного про карту в меню
17:55 - Конец

ВКонтактеYouTube
4🔥3
Media is too big
VIEW IN TELEGRAM
Всем привет!

Я продолжаю копаться в Android и его клавиатуре. Сейчас я переделал алгоритм работы с ней. Ранее я уже рассказывал про это тут. Сейчас я устанавливаю состояние однократно в начале из нашего Rust кода в нативный слой на Java и C++. И дальше получаю изменения от обоих сторон и меняю текст и в нашем коде и в нативном слое.

Теперь алгоритм доработан и можно обкатать его вместе с сетевой синхронизацией. Об этом и поговорим в видео.

ВКонтакте
2👍2🔥1
Интересная статья на хабре вышла. Пока читал в голове была только одна мысль - "казаться, а не быть". Это только кажется, что нейронки программисты могуть быть младшими коллегами. А по факту, будешь как надзиратель жестко следить за этим "коллегой", что бы он не запорол тебе проект. Отвечать то тебе. И это еще мы говорим про однотипные стандартные задачки. Что то гениальное создать пока что может только человеческая особь.
1🔥1🤯1
Как много раз я видел разработчиков, которые переделывают проект с нуля. Да и сам я грешил этим по молодости, переделывал и большие и маленькие проекты. Это было и по своей воле и по воле геймдизайнеров и по воле глав компаний. Особенно тяжело видеть как переделывается крупный проект. Сначала на дофамине, тебе кажется, что в этот раз, наконец-то ты напишешь все правильно и по уму. Но очень быстро все превращается в пытку и мучения, и ты уже мечтаешь восстановить хотя бы то, что было. А еще твои коллеги находятся в подвешенном состоянии, ожидая новый переписанный красивый проект.

Почему так происходит? Да все просто на самом деле. Код любого проекта это запрограммированная логика. Она гарантирует нам определенное поведение программы. Логика эта по сути гигантский граф состояний и переходов между ними. Переходов(связей) может быть очень много, где то они явны и понятны, а где то неявны и скрыты. Собственно чем больше логики, тем больше граф и больше связей и соответственно больше сложность. И переписывая проект, ты никуда не уберешь эту сложность. Держать всю логику крупного проекта в голове, практически невозможно. Даже в средних и крупных проектах количество состояний и связей настолько велико, что комбинаторика и сложность улетает буквально в бесконечность. Отсюда и баги, они по сути необработанные переходы из одного состояния в другое (неопределенное). Они обычно закрываются уродскими костылями. Особенно хочу отметить асинхронное программирование, это отдельный ад.

Как тогда быть?

Очевидно, что переписывать все с нуля нужно только в крайних случаях, например в устаревании или отключении технологий, как было например с flash (все переписывалось на js/ts/haxe). В остальных случаях лучше делать это постепенно, шаг за шагом, держа программу всегда работоспособной. Тут очень повезет если заранее была выбрана правильная архитектура и код разбит на модули. Если это не так, то первым шагом, можно постепенно менять архитектуру, разбивать на модули и упрощать интерфейсы. Да это больно, сложно и медленно, но возможно. Далее уже проще - постепенно переписывать модули не меняя интерфейс. И так шаг за шагом можно все привести в желаемый вид.

Удачного вам рефакторинга друзья! )
3💯2🔥1🤯1
С раннего детства меня всегда интересовали компьютерные игры. Примерно в 7 лет у меня появился первый компьютер ZX Spectrum. Это была такая толстая клавиатура-компьютер, которую просто подключаешь к ЭЛТ телевизору. А в качестве внешних накопителей использовались магнитные кассеты. Устройством для загрузки программ с кассет служил обычный магнитофон. Ох какие же эмоции были когда после пятиминутного пиуууухшхщщххсссхфххфиииииффххшшшш наконец то загрузилась с магнитофона любимая игра! А если не загрузилась эмоции были еще сильнее ))) Мы с друзьями могли играть бесконечно в эти игры выжигая телевизоры и глаза.

Однажды меня привлекли некие надписи на кнопках клавиатуры - break, goto, circle. Я понятия не имел, что это такое. Это были нечто иное как ключевые слова языка программирования Sinclair BASIC. Мой друг-сосед был постарше, который уже немного разбирался в этом, показал мне какие то базовые операции. И теперь меня интересовали не только игры - я рисовал круги и замысловатые фигуры с помощью этих команд. Я думаю, что это стало отправной точкой для меня как программиста. С тех пор играя в любую игру я задавался вопросами как она сделана. Я начал замечать разные подходы в графике и паттерны в геймплее. Я рисовал по точкам в тетрадке в клетку разных персонажей, уровни для игр и даже набрасывал какой то код. Чуть позже сосед проапгрейдил свой спектрум до 128к, а так же обзавелся дисководом. И показал мне редактор графики. Я мог залипать часами рисуя персонажей и их покадровые анимации. Особенно было интересно рисовать 3д персонажей попиксельно. Чуть позже у меня появилась Dendy и я залипал в нее. Я играл очень очень много формируя свою насмотренность. Потом у одноклассника появился PC и мы играли у него. Помню когда увидел впервые GTA2 я просто офигел! В общем везде где были компьютерные игры - Серёга в них играл.

Где то в 7-8 классе увидел у соседа книгу по компьютерной графике. Где были практически все основные алгоритмы, матрицы и т.д. Я прочитал ее от корки до корки несколько раз. Выписывал формулы и делал расчеты в тетрадках, а так же придумывал и выводил свои формулы. Тогда резко подрос интерес к математике и геометрии. Учеба (мучеба) меня никогда не интересовала. В школу я ходил исключительно ради друзей. Но вот математику, геометрию и физику очень любил. Помню были моменты когда я выводил гигантские формулы на пол тетрадки по расчету косинуса, которые выдавали значения с ужасным качеством ))). Но было очень интересно!

Мы жили не очень богато и первый PC появился у меня только на первом курсе универа. Поступил я тогда на инженера-механика, хотя всегда хотел на ПОВТ. Тогда я познакомился с такими играми как Max Payne и GTA3, навсегда ставшими моими любимыми играми. Могу играть в них часами даже сейчас. В последствие все новые игры не вызывают у меня интерес. В них как будто пропала душа. Есть красивая оболочка, но нет души. Я не вижу в них ничего нового и прорывного, ну кроме графики. Но не графика делает игру интересной, а геймплей. Если тебе не интересно играть, то супер-пупер реалистичная графика не поможет. Возможно моя насмотренность достигла какого то пика. Либо я стал больше программистом и меня интересует создание, а не потребление.

Так же меня интересовала мультипликация и компьютерная анимация. Много рисовал анимации в блокнотах и тетрадках (как тут). Было очень интересно, и так я познакомился с Macromedia Flash MX 6.0. Много анимировал всякого, и познакомился с ActionScript 2. Довольно много писал на нем, общался и изучал туториалы на flasher.ru. И нашел свою первую работу в качестве flash-developer в стартапе.

В общем игры привили мне интерес к программированию, и теперь я делаю игры! )
🔥53
Прикупил себе геймпады (XBox & Dual Sense). Теперь можно порубиться в любимые игры с комфортом. И по работе пригодится.

GTA Vice City Definitive Edition (и другие windows игры) запускаю на macOS через whisky. Тут оба геймпада заработали без настройки.

А для старых консолей типа Sega и Dendy и многих других использую эмулятор ares. Раскладку джойстиков на геймпады настроил без проблем. Играем с сыном в Battletoads & Double Dragon с удовольствием! 😁

Тот кто говорит, что на macOS нет игр - просто не умеет их готовить. 😜
👍53
Включил windows после долгого перерыва. Сделал все работы. Выключаю и на тебе - обновление! 🤬🤣😆
3