XNA/Monogame — двуединый бог инди-разработки

XNA/Monogame — двуединый бог инди-разработки

Почти всё, что вам стоит о них знать: история от древности до наших дней, краткие сведения о комплектации и подходах в разработке и причинах, по которым имеет смысл использовать или не использовать на данный момент.

Начнём издалека...

Сильно издалека. А именно, с середины восьмидесятых, когда кризис 1983 года превратил консольный рынок северной америки в выженное пепелище. В 1985 году туда пришла Нинтендо со своей NES, отстроила всё с нуля и навела там железобетонный орднунг. Конские отчисления, игры только на нашу платформу, но самое главное - строгий контроль качества. К разработке консольных игр подпускались только солидные конторы с солидными профессионалами, знающие, что они делают. Ну, хотя бы приблизительно.

Конкуренты Нинтендо, которые подтянулись попозже, тоже кого попало к разработке игр не подпускали. Шло время, усложнялись игры, увеличивались бюджеты, ресурсы и команды, необходимые, чтобы сделать игру. Конторы, подпускаемые к разработке консольных игр становились всё солиднее и солиднее. До середины нулевых разработка игр на консоли была уделом очень серьёзных фирм, у которых всё по-взрослому: с издателями и бизнес-планом. Любителям оставалось только довольствоваться разработкой игр на ПК, потому что никто тебе SDK от условной Sony PlayStation на блюдечке не принесёт, если у тебя за спиной нет команды профи и возможности вложиться сейчас и поделиться потом.

Запомнили этот момент? Точно запомнили? Отлично. Теперь зайдём с другого боку.

В конце 90-х самой модной технологией была платформа Java, которая позволяла запускать программы, написанные на одноимённом языке на миллиардах устройств от кофеварок до суперкомпьютеров. Как они это делали? Языков на самом деле было два. Сначала программа на Java компилировалась в программу на промежуточном языке, байт-коде Java, похожем на ассемблер, а потом эта "промежуточная программа" выполнялась на одном из "трёх миллиардов устройств", которыми они так любят понтоваться при установке. То, что байт-код был похож на ассемблер, делало реализацию виртуальной машины Java, непосредственно этот байт-код выполняющей, относительно простым делом. И, что самое крутое, программа на Java должна была работать одинаково на любой виртуальной машине Java. А программисты получили возможность не забивать себе голову разницей между Линуксами, Маками, Виндоусами, Интелами, Санами, Спарками и всем остальным.

Microsoft тогда был главным кандидатом на должность "корпорация зла, одержимая всемирным господством" и пройти мимо они, конечно же, не могли. Майки очень долго облизывались на Java, пытались взять модную штуку под контроль, используя юридически-корпоративную магию (всем EEE, пацаны), делали свои какие-то диалекты, но Sun на провокации не поддавались и контроль над своей драгоценной Java не отдавали.

В какой-то момент "корпорация зла" не выдержала и решила сделать свою Java, с блекджеком и шлюхами. И имя ей было .NET. Основой и киллерфичей .NET должна была стать та же идея с промежуточным языком, но развёрнутая в другую сторону. Вместо "одного языка и множества платформ" было решено сделать "много языков на одну платформу". Си-шарп, модный стильный молодёжный VB.NET, F -шарп (как использовать символ решётки без превращения его в сраный хэштег?!), свой диалект C++ и много-много других языков. "Одна платформа" - само собой, windows.

Казалось бы, зачем мелочиться? Почему бы сразу не перейти к "много языков - много платформ", используя тот самый промежуточный язык? Потому что тогда, напоминаю, Microsoft была корпорацией зла, одержимой мировым господством. Тем не менее, запирать свой .NET на миллиард юридических замков они не стали. Более того, они сделали некоторые базовые части своей технологии серьёзными международными стандартами типа ECMA-335. Главный враг всего свободного и открытого ко всеобщему удивлению занял нейтральную позицию: "Хотите .NET на Linux? PDF-ку со стандартом в зубы и вперёд. Но как-нибудь без нас, пожалуйста. Мешать не будем".

Запомнили этот момент? Точно запомнили? И прошлый тоже точно запомнили? Хорошо, тогда продолжаем.

Wild XNA appears

Ещё киллер-фичей .NET'а стала огромнейшая стандартная библиотека. WinForms, ADO.NET, ASP.NET, разные штуки для написания веб-сервисов и много-много всякого разного, что занимало две трети в обзорных талмудах по .NET'у на полторы тысячи страниц. Практически всё, что надо для нужд кровавого энтерпрайза. И, в отличие от "много языков в одном проекте", эта "киллер-фича" действительно стала киллер-фичей.

Игрострой, как ни крути, далековат от тех самых нужд, поэтому до середины нулевых пришлось перебиваться обёрткой над API-шкой DirectX'а. А потом на GDC 2004 анонсировали героя нашей истории. И спустя пару лет его выпустили. И тут настаёт момент, когда две сюжетные линии сходятся вместе. Вы же, надеюсь, помните, что я говорил о сложности разработки на консоли, верно?

Так вот, я немножко слукавил, когда сказал, что .NET поддерживал много языков, но был реализован только на Windows. Была ещё урезанная версия .NET Compact, где не было этой горы библиотек. И у Microsoft, кроме Windows, были ещё платформы, на которые можно было сделать реализацию .NET'а. Поэтому "набор инструментов" XNA, реализованный на том самом .NET Compact, позволял делать игры на Windows, Windows Phone 7 и... ща, погодьте, тут барабанная дробь должна быть ...XBox360.

Просто представьте себе это время. Разработка игр оккупирована теми самыми солидными конторами. Про слово "инди" мало кто слышал вообще. Как раз тот самый момент, когда игры уже стали успеть бизнесом, а толпа энтузиастов ещё не проломила себе дорогу в прессу, в розницу и в сердца игроков. Стим тогда использовался для того, чтобы было легче докидывать патчи для контры до всех играющих. GreenLight даже в проекте не намечался. Я уж молчу про KickStarter. На момент анонса XNA даже Gish ещё не вышла (первая игра Эдмунда Макмиллена и пары его товарищей, после которой люди с некоторым удивлением начали вспоминать, что когда-то хорошие игры делало меньше пятидесяти человек).

И тут на белых конях влетают такие хлопцы из игрового подразделения Microsoft и выдают: "Пацаны, Visual Studio с парой плагинов и сотка баксов за аккаунт в XNA Creators Club - и вы сможете разрабатывать крутые игры для самой лучшей Nextgen-консоли (нашей, конечно), не выходя из подвала! Студентам тех. вузов бесплатно!". Чуть позже, в 2007 году ребята из Microsoft подтвердили серьёзность своих намерений и запустили Xbox Live Indie Games, где маленькие команды и психи-одиночки пилили своё инди для магазина XBox и продавали его по сравнительно небольшим ценам. Кстати, членство в XNA Creators Club было нужно только для разработки игр на XBox. Для разработки на иные платформы нужно было скачать только сам XNA и поставить его поверх Visual Studio. Это уже было серьёзной заявкой на народную любовь.

Но нет, это было ещё не всё. Как выяснилось позже, изнутри XNA оказался хорош. У меня такие тёплые воспоминания кроме работы с XNA, вызвало только API Telegram'а на python. На этой штуке было действительно приятно писать и работать. Никлаус Вирт в своё время сделал язык Pascal, чтобы учить людей программированию, но оказалось, что на нём можно писать нормальные программы. С XNA получилось наоборот. То, что задумывалось как набор инструментов для реальной разработки, оказалось ещё и отличной площадкой для обучения студентов ООП. В общем, даже если игру мечты соорудить не удавалось, XNA оставлял о себе, в основном, приятные воспоминания, как бывшая с которой разошлись полюбовно и действительно остались друзьями.

И пошло-поехало. Игры разрабатывались, книжки типа "учимся программировать с помощью XNA" писались, документации было навалом, как и к другим библиотекам .NET от Microsoft. Жизнь была хороша. И была она хороша приблизительно до 2011-2012 года, когда вышла последняя версия XNA 4.0 Refresh.

Проходящая любовь, вянущие помидоры

Где-то с конца 2011 года сообщество было несколько обеспокоено судьбой XNA. Майки ушли в молчанку по поводу новых версий, а поддержку Windows 8, новых Metro-интерфейсов и прочих модных штук добавлять не хотели. Лишь спустя год, в начале 2013, в какой-то почтовой рассылке журналистам Microsoft между делом подтвердила, что на XNA давно и окончательно забит болт, новых версий уже точно больше не будет, да и поддержку старых в 2014 году прекратим.

Пять лет всё было неплохо. Что же пошло не так в районе 2011-2012 года, что Microsoft решили забыть о своём детище? Точные причины мне, увы, не известны, поэтому этот раздел статьи будет упражнением в конспирологии. Предлагаю тем, кто знает больше, присоединиться в комментариях. Далее три возможные причины. Как мне кажется, каждая из них повлияла. Но в какой степени, я даже близко определить не берусь. Расположу их в порядке возрастания важности, как мне самому видится.

Первое - недостаточный финансовый выхлоп.

Вообще вся деятельность вокруг XNA немножко смахивала на меценатство. XNA был бесплатен для всех, кто имел Visual Studio и не собирался разрабатывать на XBox. Да, в Xbox Live Indie Games вышло, если википедия не врёт, больше трёх тысяч игр. И это, скажем так, очень много. Но много ли в Microsoft имели от их продажи? Не факт, что на разработку этой библиотеки было потрачено очень много, но кому-то среди большого начальства могло прийти в голову, что нечего на этих дармоедов тратить деньги. Тем более, Microsoft где-то около этого момента решили немного сменить направление.

Второе - смена направления игровым подразделением Microsoft.

21 мая 2013 года. Microsoft, ружьё, нога, выстрел.

До сих пор помню некоторое удивление, которое я испытал, когда решил посмотреть презентацию XBox One. Я не знаю, кому в голову пришла светлая идея, что приставка нужна исключительно для того, чтобы на ней было удобно телек смотреть и иногда зарубать в фифулю. Я не знаю, зачем этого человека выпустили из больницы. Но я точно знаю, что за один день такие решения не принимаются, а значит они планировали этот гениальный ход "задолго до". И это "задолго до" середины 2013-го года как раз наслаивается на тихую смерть XNA. Судите сами, для новых Metro-веяний XNA никто адаптировать не стал, а на XBox One всякие XNA, видимо, были не нужны. Зачем, если есть возможность посмотреть телек. Справедливости ради скажем, что не сразу, но они осознали и одумались. Правда, к тому моменту воскрешать XNA было поздно. Да и не было необходимости. Ведь появились альтернативы.

Третье - появление альтернатив.

Точнее, альтернативы. Unity. Появился тоже где-то в середине нулевых, развивался параллельно и метил в ту же целевую аудиторию, по сути. Как бы это поточнее описать разницу между Unity и XNA. Начать хотя бы с того, что Unity сходу предлагает тебе редактор и несколько туториалов, где можно порасставлять модельки, а не пугает с порога до усрачки пустым проектом в Visual Studio, где это "порасставлять модельки" тебе придётся набирать своими ручками. Всё-таки Unity был уже готовым игровым движком. Этакий Unreal на минималках, доступный всем и каждому. Если я ничего не путаю, тогда Epic games не раздавали миллионы долларов инди-разработчикам за здорово живёшь. А XNA был скорее набором библиотек с минимальным каркасом, позволяющим назвать его фреймворком и парочкой утилиток для конвертации ассетов в формат xnb, используемый библиотекой. Если XNA был набором кухонных ножей и посуды, то Unity был кухонным комбайном. Да и список платформ не ограничивался тем, что предлагал Microsoft.

Так бы история XNA и закончилась бы, если бы не любовь сообщества и один момент, который я просил запомнить раньше.

Птица феникс

Ну что, пришла пора дать второй залп из чеховского ружья. Помните, я говорил, что Microsoft не стали запирать .NET на миллиард юридических замков? Так вот, популярность .NET'а привела к тому, что группа энтузиастов взяла спецификацию в зубы и засучили рукава, чтобы сделать реализовать всю эту прелесть на Linux. Microsoft открыли в виде стандартов только самое ядро системы. Это означало, что всё, за что .NET ценят и любят, всю стандартную библиотеку придётся реализовывать заново с нуля. Но это никого не остановило и на свет появился проект Mono. Так на Linux'е появилась возможность писать программы на .NET. Не сразу, но там появлялась и огромнейшая стандартная библиотека, созданная Microsoft. Как это случались, если стандартная библиотека была закрытой и отдавать исходники никто не собирался? Её просто писали заново с расчётом на то, чтобы работало как в .NET.

Тот, кто имел дело с .NET и приблизительно представляет, сколько там всего нужно было написать заново, на этом месте может уважительно присвистнуть. Поверьте, написать заново хотя бы тот же ADO.NET дорогого стоит. И что, как вы думаете, случилось, когда Microsoft бросила полюбившийся многим разработчикам видеоигр инструмент? Комьюнити решило "что нам стоит дом построить" и взялось реализовывать фреймворк заново. Причём попытка была не одна. Мне известно как минимум о FNA и Monogame. Допускаю, что есть и другие реализации. Но по-настоящему "взлетел" именно Monogame.

История его не столь хорошо мне известна, потому тут просто скажу, что делать его начали ещё до того, как закатилась звезда XNA. Чтобы, как гласит твиттер проекта, донести удовольствие от работы с XNA 4.0 до немайкрософтовских платформ. Но когда стало ясно, что "король умер", комьюнити возвестило "да здравствует король" и Monogame получил почти весь приток внимания, доставашийся его предшественнику. Так как исходник Monogame был ещё и доступен всем желающим, комьюнити могло принять участие в разработке. И оно приняло. Если верить гитхабу, в ветке develop на данный момент отметилось 262 человека, а активных разработчиков у Моногейма не наберётся и десяти человек.

К 2017 году гениев маркетинга из Microsoft окончательно отпустило и они возродили свою старую инициативу по продвижению инди-игр на XBox под именем "Xbox Live Creators Program" для игр написанных на UWP, их сравнительно новой APIшке, позволяющей запускать один и тот же код на всех устройствах, где есть Microsoft Store. Так как Monogame на тот момент поддерживал UWP, круг замкнулся и возрождённый из пепла XNA окончательно вернулся, пусть и под другим именем.

Дальше расскажу о некоторых отличиях Monogame от XNA, с которыми столкнулись разработчики. Точнее, двум из них.

Всё было, но не сразу

Первое касается трудностей переходного периода. Невозможно реализовать всё сразу, поэтому те, кто перешёл сразу были обречены на то, чтобы время от времени натыкаться как на грабли на вылетающее NotImplementedException. Не исключаю, что и сейчас можно на такое наткнуться. Хотя на десятом году разработки фреймворка шанс, конечно, мизерный. Но отсутствие какого-нибудь нетривиального метода в Monogame ещё не катастрофа. Серьёзной проблемой было другое.

Все ассеты в XNA конвертируются во внутренний формат xnb. И вот с перегонкой этих ассетов, то бишь с Content Pipeline возникли трудности. Как вообще проходит работа в Visual Studio? Ты добавляешь в проект текстовые файлы с исходным кодом, просишь студию собрать проект и он превращает твои потуги в программу. Возможно, даже рабочую. Как происходила работа с ассетами в XNA? Представьте себе, точно так же! Ребята из Microsoft поставляли с набором библиотек расширение для Visual Studio, которое, если я правильно помню, называлось Content Pipeline. Ты создавал специальный проект, в который вместо исходного кода добавлял модельки, спрайты, звуковые эффекты, шрифты, а потом при компиляции всё это добро перегонялось в xnb. В одном проекте файлы с кодом, в другом картинки, которые, если мне не изменяет память, можно было даже посмотреть прямо в Visual Studio.

В это была определённая логика, надо заметить. Вот только разработчикам Monogame от этого было не легче. Так как это был жирный кусок, который откладывался до последнего (я сталкивался с этим ещё в 2013-2014 году), то перегонка ассетов в xnb на Monogame долгое время осуществлялась по такой чудной схеме: а) поставить себе Monogame, использовать его для разработки самой игры, б) поставить себе XNA, складывать в проект xna ассеты, в) совмещать и плакать в процессе этого странного акта некрофилии. Сидишь на Макоси и хочешь разрабатывать игры на Mono и Monogame для любимой оси? Ага, щас, держи карман шире. Добро пожаловать обратно на винду! В конце концов, аж в начале 2015 года была создана отдельная утилита для преобразования ассетов. Почему в Monogame это делалось отдельно от Visual Studio? Вот тут-то и переходим ко второму отличию.

Круче только Unity

Monogame не просто так назывался. Целью проекта Mono было разделение двух понятий "разработка на .NET" и "разработка на платформы Microsoft" на две большие разницы. Monogame как бы своим названием намекал, что Microsoft спасибо за всё, но на XBox и Windows свет клином не сошёлся, а мы идею Mono переносим на геймдев. Собственно, везде где можно разрабатывать на Mono (а это как минимум троица Win/Linux/Mac и там даже своя IDE MonoDevelop имеется), можно разрабатывать игры для следующих платформ:

  • Android
  • iOs
  • Windows
  • Linux
  • MacOS
  • XBox One
  • PS4
  • PSVita
  • Switch
  • OUYA. Кто-нибудь вообще помнит, что это такое? На кикстартере большущие деньги на проект собрали. Было бы интересно почитать, почему оно загнулось.
  • В общем, если на этом можно запускать игры (DOOM и Skyrim не в счёт), то команда Monogame попытается туда добраться.

И чего в нём можно делать?

Рассказывая о возможностях Monogame/XNA, отмечу пару важных моментов "продававших" XNA разработчикам:

1) Минимум кода для того, чтобы сделать что-то. Я понимаю, что "три строчки на вывод спрайта на экран" никого теперь не впечатлят. Но тот, кому до этого доводилось работать напрямую с DirectX плакал от счастья, когда отпадала необходимость тратить на это десятки строк.

2) Универсальность. Код максимально отвязан от платформы. Конечно, есть какие-то очевидные моменты, вроде управления через сенсорный экран или геймпад. Но везде, где это возможно, код будет одинаков для всех платформ.

3) Момент, не столько продающий, сколько определяющий нишу Monogame/XNA в эпоху развитого индипостапокаллипсиса. Низкоуровневость. Или минимализм. Что я под этим подразумеваю? Ситуацию, когда а) есть всё необходимое, б) и ничего больше. О плюсах и минусах этого подхода, в зависимости от ситуации, можно спорить долго и до посинения. Надеюсь, по ходу повествования эти самые плюсы и минусы станут очевидны.

Теперь давай по порядку рассмотрим, чего же в XNA можно делать. Если я вдруг переборщу с техническими деталями, перематывайте до плюсов и минусов.

Двухмерный графон

Здесь вам позволено, по большому счёту, две вещи:

1) Нарисовать спрайт в определённом месте экрана. Спрайт можно повернуть, отмасштабировать, отразить. Можно нарисовать часть спрайта. Скелетная анимация? Ну, вы можете запрограмировать это сами. Хотя бы покадровая анимация? Ну, почему бы и нет. Можно ведь нарисовать часть спрайта. Делаете раскадровку на одном png-изображении и рисуете часть спрайта, соответствующую текущему кадру. Да, только самое необходимое.

2) Нарисовать текст. К счастью, нас не будут заставлять делать спрайт для каждой буквы и распихивать их на экране. Через Content Pipeline в xnb можно перегонять шрифты (и в комплекте с XNA даже шло десять бесплатных штук), а потом попросить отрендерить текст в нужной позиции этим шрифтом. Ещё можно узнать, сколько места займёт конкретная строка текста. Очень полезно, когда нужно поместить хп босса прямо у него на головой, например. Или прикинуть, поместится ли текст в окошке.

И... Это всё. Но в умелых руках достаточно и этого.

Управление

Ну, тут просто перечислим.

  • Геймпад. Крестовина, стики, триггеры, вибрация и кнопки. Список кнопок достался в наследство икс-боксовый, конечно. Для нестандартных устройство предусмотрен следующий пункт списка.
  • Джойстики. Отличаются в Monogame тем, что там может быть любое количество осей, кнопок и прочих дёргательных приспособлений.
  • Клавиатура. Проверка нажата ли кнопка в данный момент, а так же список нажатых кнопок.
  • Мышь. Кнопки, позиция курсора на экране, позиция колёсика в формате "сколько намотано с начала игры". Можно поставить курсор в нужную тебе позицию. Можно изменить его вид или вовсе спрятать его.
  • Сенсорные экраны. Тут можно получить список прикосновений к экрану (знаю, звучит слишком по программерски) и узнать, как двигались пальцы по экрану. Нам дают не только позиции, но и состояние, типа, "палец передвинулся, палец прижали, палец отпустили". Тут разработчики XNA внезапно расщедрились и добавили базовое распознавание жестов, видимо, посчитав, что уж это-то точно понадобится всем. Можно не мучаться с координатами в голом виде, а просто спрашивать, что делает пользователь с экраном. И нам расскажут, если заметят, о тычке пальцем в экран, двойном тычке пальцем в экран, о том, что палец уже секунду, а то и больше, держат на одном месте, о вертикальном и горизонтальном перетягивании, о просто перетягивании, о быстром единичном дёрге пальцем, о стягивании двух пальцев в одну точку. Если же вам этого вдруг не хватит... *тяжкий вздох* ..."голые" координаты "как есть" к вашим услугам. Опять-таки, самое необходимое.

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

Аудио

Когда-то для работы со звуком для разработки под XBox поставлялась отдельная утилита, которая называлась XACT. Позже её переделали, чтобы ею можно было пользоваться и для разработки под Windows. И её даже включили в DirectX SDK. Позже эта утилита оказалась в наборе XNA. Поддержка XACT закончилась ещё раньше поддержки XNA и, честно говоря, я не знаю придумали ли в Monogame что-нибудь на замену. Даже если нет, обратная совместимость с кодом XNA никуда не исчезает. Сталкиваться близко с этой программой мне не доводилось. Подозреваю, что это тема для отдельной статьи. Поэтому тут я вкратце расскажу о возможностях, предоставляемых тем, кто не хотел с XACT связываться.

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

Для музыки есть такая штука, как "медиа-плеер" (имя отчество полностью Microsoft.Xna.Framework.Media.MediaPlayer), этакий внутренний мини-winAmp, где ты можешь составить плей-лист из mp3-песен, включить их одну за другой или случайно. Или оставить одну и ту же на повторе.

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

С этого места давайте чуть-чуть поподробнее, чтобы вы как следует прочувствовали, что в данном контектсе значит слово "низкоуровневый". У вас есть возможность, используя магию рядов Фурье, цифровой обработки сигналов и иных математических колдунств, преобразовать звуковые волны, которые должны звучать в вашей игре в набор цифр от 0 до 255, собрать их в один массив, указать частоту в герцах для всего этого счастья и скомандовать "Play". Кому вообще может такой изврат прийти в голову? Ну, как вариант, таким макаром можно сделать очень правдоподобный закос под какое-нибудь древнее устройство, где в качестве звукового чипа была относительно простая "пищалка". Или даже не совсем простая. Я тут, пожалуй, оставлю ссылку на туториал для тех, кто уже хоть чуть-чуть работал с XNA или Monogame. Там в трёх частях описывается, как с помощью XNA и сотни-другой строк кода написать синтезатор. Ещё замечу, что когда я в последний раз проверял (то ли 2013, то ли 2014), в Monogame конкретно эта возможность была недоступна из-за того, что "мы хз как это реализовать на всех платформах". Но теперь в документации пишут, что всё поддерживается.

Наверняка вам захочется обойтись файлами и вы предпочтёте не использовать никаких описаний звуковых эффектов байтовыми массивами. Точнее, вы даже в рот сношали все эти байты и хотите работать исключительно с файлами. Но тут вы обнаруживаете, что есть поддержка микрофона и было бы мило организовать что-нибудь вроде чата или звукового управления. *нервный смех* Угадайте, как осуществляется работа с микрофоном в XNA/Monogame?

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

Мультиплеер

Часть возможностей XNA была недоступна на Windows Phone 7. И этой частью был мультиплеер, который организовывался через Games for Windows LIVE и его аналог для XBox360 XBOX Live. Так как это фича была исключительно для платформ Microsoft и эти сервисы уже чуть-чуть умерли, в Monogame это больше не поддерживается. Причём что интересно, в Microsoft считали, что не нужно даже этого и добавили доступ к лайв-сервисам только во второй версии по многочисленным просьбам трудящихся. Какие альтернативы предлагались изначально и какие альтернативы ныне предлагаются в Monogame?

"Пацаны! Вся стандартная библиотека .NET к вашим услугам! С помощью классов из System.Net вы можете отправить UDP-пакет на любой IP-адрес на этой планете! Клёво, да?" Что тут ещё сказать? Тогда действительно считалось, что лучший выбор для разработчиков мультиплеерных игр - это стандартные библиотеки для работы с сокетами. Тот, кто понял последние два предложения, уже вовсю прочувствовал, что значит слово "низкоуровневый" в контектсе данной статьи. Как и в случае с обработкой ввода с микрофона, имеет смысл озадачиться поиском сторонних библиотек.

Ну и всегда есть "план Б": сплит-скрин на четырёх человек. Да, именно на четырёх. И если вы внимательно читали, то вы, возможно, представляете, почему именно на четырёх и как это реализовать.

Трёхмерный графон

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

Начнём парад невероятных возможностей 3D в XNA с возможности рисовать примитивы. Причём, что занимательно, двухмерный примитив нарисовать нельзя, только двухмерную текстуру, то бишь двухмерный спрайт. Хочешь нарисовать зелёную линию - только в 3D. Зато у вас такие возможности по рисованию треугольничков! Или четырёхугольничков. Хочешь нарисовать квадрат в 3D? Всё просто, создаёшь массив из четырёх вертексов и рисуешь их, не забыв указать, что это TriangleStrip. Не знаешь, что такое TriangleStrip? Придётся узнать. Зато натянуть на этот квадрат текстуру можно в три строчки.

Итак, модели. Учебники по XNA говорят нам, что мы можем загрузить модель в формате .x вместе с сопутствующими текстурами. И для их изготовления рекомендуют использовать blender. И вот тут разработчики отступили от своего "минимум кода" и вы сразу сталкиваетесь с тем, что нельзя нарисовать модельку одной строчкой, вызвав какой-нибудь Model.Draw. Видимо, игроделам таким макаром хотели намекнуть, что они обязаны разобраться в некоторых деталях и проконтролировать их.

Видит бог, не хотелось мне этого делать, но я вынужден добавить сюда парочку примеров кода. На rbwhitetaker.wikidot.com минимальный код для рисования модели выглядит так:

private void DrawModel(Model model, Matrix world, Matrix view, Matrix projection) { foreach (ModelMesh mesh in model.Meshes) { foreach (BasicEffect effect in mesh.Effects) { effect.World = world; effect.View = view; effect.Projection = projection; } mesh.Draw(); } }

В книге Аарона Рида "Learning XNA 4.0" минимальный код для рисования модели выглядит так:

public void Draw(Camera camera) { Matrix[] transforms = new Matrix[model.Bones.Count]; model.CopyAbsoluteBoneTransformsTo(transforms); foreach (ModelMesh mesh in model.Meshes) { foreach (BasicEffect be in mesh.Effects) { be.EnableDefaultLighting(); be.Projection = camera.projection; be.View = camera.view; be.World = GetWorld() * mesh.ParentBone.Transform; } mesh.Draw(); } } public virtual Matrix GetWorld() { return world; }

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

"Низкоуровневый" - это не значит "ограниченный". В XNA у вас была возможность использовать самолично написанные на HLSL шейдеры. HLSL - это язык для написания шейдеров, используемый в DirectX. N.B. Если я всё правильно понимаю в этой жизни, шейдер - это программа, которая выполняется непосредственно видеокартой. Что забавно, для отрисовки модели со своим шейдером кода нужно было почти столько же, сколько просто для отрисовки модели. Приведу опять пример с rbwhitetaker.wikidot.com:

private void DrawModelWithEffect(Model model, Matrix world, Matrix view, Matrix projection) { foreach (ModelMesh mesh in model.Meshes) { foreach (ModelMeshPart part in mesh.MeshParts) { part.Effect = effect; effect.Parameters["World"].SetValue(world * mesh.ParentBone.Transform); effect.Parameters["View"].SetValue(view); effect.Parameters["Projection"].SetValue(projection); } mesh.Draw(); } }

Нарисовать модель со своим шейдером (в коде XNA он называется Effect) и нарисовать модель без своего шейдера - приблизительно одни и те же затраты кода в си-шарпе. Похоже, XNA таким образом намекает нам, что лучше рисовать модели со своими шейдерами.

В Monogame используется тот же HLSL даже для проектов, использующих OpenGL. Да, в OpenGL свой язык шейдеров, называющийся GLSL, но в Monogame всё равно используется HLSL, который при надобности перегоняется в GLSL. Для тех, кто хочет всё же использовать GLSL, существует отдельная ветка репозитория Monogame. Подробности искать тут:

Собственно, это всё. Системы частиц? Материалы? Тени? Освещение? Вперёд, пишите, всё необходимое у вас есть. Да, вот этими вот руками. Ну, или ищите сторонние библиотеки.

Как всё это счастье организовано?

Ну а теперь, собственно, рассказ о той части, которая позволяет называть XNA фреймворком, а не набором библиотек. А именно - архитектурный каркас. В XNA ваша игра пишется внутри своей вариации встроенного класса Game. Что он делает? Прячет внутри себя игровой цикл.

Честно спионерено из книги Аарона Рида "Learning XNA 4.0"<br /> Aaron Reed<br />
Честно спионерено из книги Аарона Рида "Learning XNA 4.0"
Aaron Reed

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

Initialize - Название говорит само за себя. Тут выполняются все подготовительные действия, кроме загрузки ассетов.

LoadContent - А тут выполняется загрузка всех необходимых ассетов.

Дальше идёт игровой цикл, который образуется из вызовов Update и Draw. По умолчанию, Update и Draw вызываются 60 раз в секунду (те самые 60 FPS). Эту цифру, если хотите, можно изменить. Сначала вызывается Update, где вы обновляете состояние игры. Следом сразу же вызывается Draw, где вы рисуете текущее состояние игры.

Почему игровой цикл разделили на Draw и Update? Дело в том, что XNA честно попытается обновить вашу игру 60 раз в секунду, но гарантировать этого, ясное дело, не сможет. На случай, если XNA не будет успевать, имеются следующие меры. Во-первых, будут пропускаться вызовы методы Draw. Именно поэтому там должна быть только отрисовка игрового мира и никакой логики, связанной с его изменением. Во-вторых, в Update вы будете получать информацию о том, сколько времени прошло с прошлого вызова, чтобы вы ориентировались на то, сколько на самом дел прошло времени. В третьих, вы можете в любой момент проверить флажок IsRunningSlowly. Если он выставлен в True, то можно уже самому принять меры, подровняв дальность отрисовки, отрисовав текстуры с меньшим разрешением, намекнув пользователю, что что-то пошло не так, или записав себе куда-нибудь в лог информацию о проседаниях.

В самом конце, когда уже игра закончилась, вызывается UnloadContent. Не надо пугаться, XNA сам приберёт ассеты из памяти. Зачем же тогда он есть? Дело в том, механизм загрузки ассетов расширяем. То есть, вы можете написать свой загрузчик/обработчик, если вы хотите загрузить что-то в нестандартном формате. На случай, если ваши расширения потребуют каких-то дополнительных телодвижений при выгрузке ассета из памяти, добавлен этот самый метод UnloadContent, в который можно вклиниться.

Компоненты

Кроме скрытия игрового цикла этот самый класс Game содержит коллекцию игровых компонентов. Что это такое? В XNA игровым компонентом называется обрезанная версия класса Game GameComponent, где остались только методы Initialize, Update, и DrawableGameComponent, где есть весь набор - Initialize, LoadContent, Update, Draw и UnloadContent. Вы можете запихнуть части вашей игровой логики в эти самые компоненты. Потом уже непосредственно в вашей вариации класса Game вы можете добавлять компоненты, включать и выключать их, прятать и показывать их. Как это работает? Сначала ваш Game выполняет в Update или Draw то, что ему предписано вами, а потом просто проходится по списку имеющихся компонентов и обновляет/отрисовывает их, если они включены. Что таким макаром можно делать? Ну, я накидаю приблизительный список, но это список из разряда "что можно нарисовать простым карандашом". При достаточно развитых терпении и воображении этот список безграничен.

  • Части интерфейса можно раскидать по разным компонентам и делать их видимыми/невидимыми по ситуации.
  • Отдельный компонент для отладочной информации, вроде количества FPS.
  • Компонент, внутри которого непосредственно происходит игровое действо, можно оставить видимым, но при этом отключить его обновления. Это, чуть что, самый простой способ поставить игру на паузу.
  • И сразу же можно сделать видимым компонент "игровое меню".
  • Если у вас будет отдельный компонент на каждый уровень, вы сможете загружать ассеты отдельно для каждого уровня.
  • Некоторые любят отделять в игровые компоненты управлении вводом и ИИ.

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

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

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

Причины не использовать XNA/Monogame

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

  • Вам хочется использовать невероятно крутое и технологичное 3D. И вам никто не запретит его использовать. Только для этого надо его написать. С нуля. Без множества подкованных по теме "человеко-месяцев" это невозможно.
  • Вам хочется использовать хоть какое-нибудь 3D. Тут уже всё не так страшно, и этот пункт здесь постольку-поскольку. Но надо учитывать, что для 3D игра XNA/Monogame используют реже. А значит, тестируют меньше. Отсюда следует больший шанс наткнуться на какую-либо проблему.
  • У вас нет опыта программирования и вам очень сильно не хочется его приобретать. А ещё вы любите визуальные редакторы. Тогда мои вам соболезнования. Ну а если серьёзно, то XNA/Monogame - это не игровой движок, а именно что фреймворк с парой утилиток, облегчающих программисту работу. Хотя, повторюсь, никто не запретит сделать игровой движок на его основе.
  • Вам нужна самая свежая и полная документация + вы целитесь в мультиплатформу. Так, этот грех касается исключительно Monogame. Так исторически сложилось, что к XNA была достаточно полная документация, гора туториалов и немалое количество книг. И хвала богам, что это всё из интернета никуда не исчезло (по состоянию на февраль 2019 года). Увы, с Monogame в этом плане всё куда печальнее. Спасает только то, что всё написанное об XNA с некоторыми оговорками применимо и к Monogame. Не удивляйтесь, если вдруг окажется, что книга написанная до того, как Monogame вообще начал существовать, прояснила вам больше официальной документации Monogame.
  • Вам нужно чтобы что-то нетривиальное работало из коробки. Ну, этот пункт должен быть очевиден из вышеописанного. Например, если вы хотите физику "из коробки", то придётся смотреть в сторону чего-то более солидного. Или искать какую-нибудь библиотеку, ставящуюся поверх XNA. Или писать самому.

Причины использовать XNA/Monogame

  • Вам нужен абсолютный контроль. Обратная сторона пресловутого минимализма. Да, написать свою физику сложнее, чем взять готовый вариант в каком-нибудь Unreal Engine. Но это будет ВАША физика. Вы будете знать всё о том, как она работает в вашей игре. И сможете изменить её, как вам заблогарассудится. Отсутствие готового варианта = отсутствие ограничений с ним связанных. Нужен постоянно изменяющийся хит-бокс в форме четырёхмерного бублика, срабатывающий только во время определённых фаз луны? На здоровье, Си-шарп исполнит любые ваши желания, стоит только суметь попросить.
  • Бонус к предыдущему пункту: бесценный опыт. Тот, кто написал свою физику уже не будет бояться разобраться с уже готовой библиотекой. И это касается не только физики.
  • Вам нужен простой инструмент, не требующий отдать пол-жизни на его освоение. Обратная сторона минимализма, опять же. Серьёзные игровые движки представляют собой необъятные инструменты, освоение которых потянет на отдельную профессию. С XNA вам будет достаточно почитать две-три книги, поковыряться в документации, создать парочку прототипов и вы, считай, уже полностью в нём разобрались.
  • Из графических изысков планируется только простенькое 2D. Выводится текст, выводятся спрайты. Есть средства для того, чтобы это проконтролировать. Чего ещё для счастья нужно? По крайней мере, очень многие разработчики мыслят в этом ключе.
  • Вы не хотите иметь дело с визуальными редакторами. Ну, мало ли. Частично пересекается с первым пунктом.
  • Мультиплатформа, детка. Пункт добавлен исключительно для галочки, так как мультиплатформенность нынче чуть ли не стандарт для любого уважающего себя средства разработки. Тем не менее, автор Dust: An Elysian Tail наверняка был рад возможности выпустить свою метроидванию на iPad и Switch.

ВДНХ, или глава в которой наконец-то появляются картинки

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

Я не знаю, что тут больше повлияло, мои вкусы или специфика инструмента, но список получился немного однобоким. Список составлялся по принципу "о чём слышал, во что играл"

Stardew Valley

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

Честно признаюсь, не играл, а в список включил из-за её известности. Если вдруг кто-то о ней не слышал, то игра представляет из себя "весёлую ферму" здорового человека. Аддиктивна до ужаса, обласкана критиками.

XNA/Monogame — двуединый бог инди-разработки

Fez

Канадский инди-разработчик Фил Фиш известен двумя вещами. Термоядерным нытьём, на фоне которого уважительно снимали шляпу шитштормы геймергейта, и необычным платформером Fez, вышедшим в 2012 году.

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

Признаюсь честно, мне не зашло, но тем, кто любит всякое разное необычное, попробовать обязательно.

XNA/Monogame — двуединый бог инди-разработки

Axiom Verge

Инди-метроидвания, сделанная по всем возможным канонам жанра. Прям вот любовное послание жанру. Пять лет сплошного непрошибаемого "Я ЛЮБЛЮ METROID И ВЫ ЕГО, СУКИ, ТОЖЕ ПОЛЮБИТЕ", скристаллизованного в одной игре. С бек-трекингом, множеством способностей, нетривиальным сюжетом, полностью раскрыть который можно только выдрочив там всё до последнего пикселя, и отличнейшим саундтреком. Мои глубочайшие респекты Томасу Хаппу и мои искреннейшие рекомендации к скачиванию/покупке.

XNA/Monogame — двуединый бог инди-разработки

Terraria

А теперь, ради разнообразия, об играх которые делает больше двух человек (вроде бы). Появилась на волне популярности Minecraft, но звание "двухмерный клон" быстро переросла. Сделана именно на XNA.

XNA/Monogame — двуединый бог инди-разработки

Hell Yeah!™ Wrath of the Dead Rabbit

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

Вообще, что странно, игра вроде как сделана на XNA. PC-версия так точно. Но вот то, что игра вышла в 2012 году на Xbox360, PS3 и PC одновременно наводит на некоторые мысли. Неужто воспользовались Monogame?

XNA/Monogame — двуединый бог инди-разработки

Celeste

Игра знатно пошумела среди ценителей видеоигр и даже взяла на The Game Awards 2018 приз за лучшую инди года, так что много о ней писать не буду. Скажу только, что свои призы она заслужила.

Да, Celeste разрабатывалась на XNA. Причём в разработке было задействовано аж три реализации: XNA, FNA и Monogame.

XNA/Monogame — двуединый бог инди-разработки

Bastion, Transistor, Pyre

Почему три штуки за раз? Потому что они схожи по стилю и сделаны одной студией - Supergiant Games. Этот случай несколько выбивается из списка. Тут целая студия, пусть и инди-студия, сделала XNA/Monogame своей основной технологией и успешно выпустила на нём три игры подряд. Три, потому что я не смог нагуглить на чём именно сделан Hades. Но если вдруг кто-то играет, проверьте нет ли там папки Content в которой лежат xnb-файлы. Это выдаст родство с XNA с головой.

Кстати, я не поленился, залез в код Transistor (программы на .NET ОЧЕНЬ легко декомпилируются), чтобы выяснить, двухмерная или таки трёхмерная графика в игре. И оказалось, что там всё рисуется через SpriteBatch. То есть, вся эта красота, которую вы могли там наблюдать, скорее всего сделана через двухмерную графику. И, судя по некоторым косвенным признакам, там они таки обработали Monogame напильником под себя.

Я оставлю тут картинку с официального сайта Transistor, потому что я играл только в неё.<br />
Я оставлю тут картинку с официального сайта Transistor, потому что я играл только в неё.

Dust: an Elysian tale

Вот это я берёг напоследок. До самого конца, когда вы уже будете думать, что одиночки на XNA делают только пиксельный графончик. Мой личный фаворит, демонстрирующий, на что способен XNA в прямых руках.

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

Разработка началась ещё в 2008 году и изначально Дин хотел выпустить её через XBox Live Indie Games, но его вовремя заметили в Microsoft и в 2009 году его переподписали на XBox Live Arcade. В какой-то момент выяснилось, что разработать игру за три с половиной месяца, как изначально планировалось, не получится. Но ступившегося на путь длиной в три с половиной года Додрилла было уже не остановить.

В 2012 года она вышла на XBox. Позже автор игры, видимо, открыл для себя Monogame, и игра начала расползаться по платформам, как тараканы после того, как ты включишь свет. К PC и XBox со временем добавились PS4, Linux, OS X, iOs и, в конце 2018 года, Nintendo Switch.

Почему я уделяю этой игре столько внимания? Скажем так, геймплейно это не лучшая метроидвания во вселенной. Само собой, добротная, хорошая, но не сверхкрутая. Но визуальная часть местами такая, что Ори нервно курит в сторонке вместе со всем своим слепым лесом. Ты как будто зашёл на Девиант-арт в галерею очень крутого художника, а она внезапно ожила, веб-страница куда-то исчезла, остался только этот нарисованный мир, у тебя в руках почему-то геймпад, и ты уже идёшь разбираться с амнезией главного героя в компании какой-то летающей прелести непонятной видовой принадлежности. Короче говоря, рекомендую. В стиме скидка 75% до 11 февраля, кстати. Лучшего способа вложить два с половиной доллара придумать трудно.

Этот кадр я утащил из Стима. Игра действительно так выглядит.<br />
Этот кадр я утащил из Стима. Игра действительно так выглядит.

Чё ещё почитать

Книг по XNA немало, но среди них выделяется "Learning XNA 4.0" Аарона Рида, которую я тут не раз упоминал.

Так же очень хвалят туториалы, которые можно найти тут:

Можно исследовать официальную документацию Monogame:

Но документации по XNA всё-таки будет получше. Хотя бы потому, что там описания классов и свойств всегда содержат что-то, кроме имени класса или свойства. Надеюсь, эта ссылка не умрёт через месяц:

Конец

Ну, вот и всё, что я могу рассказать об Monogame/XNA. Сразу скажу, что мой опыт ограничен, а догуглить/дочитать недостающее не всегда возможно. Так, например, я ясно вижу, что этой в этой статье не хватает обзора библиотек, которыми люди расширяют не слишком большой функционал этого фреймворка. Ведь за столько лет наверняка уже много чего написано для преодоления ограничений XNA. А мне известно только про Monocle, которым пользовался автор Celeste.

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

P.S.

Написание таких статей работа, на которую уходят силы и время. Если вам кажется, что эта работа достойна оплаты, то всё в ваших руках:

137137
42 комментария

Шикарный жирнейший пост, моё уважение.

17
Ответить

Будучи разбалованным движками, читал и испытывал боль, представляя процесс разработки.
Ныне, если хочется как можно больше контроля, при этом иметь нормальный редактор и крутой менеджер сцены, оптимальным выбором будет Godot Engine. Код полностью открыт, MIT-лицензия, сносная документация, ежедневные ночные сборки. Это позволяет отпилить всё, что не нравится и написать с нуля в приступе садомазохичного исступления.
Что ещё можно сказать? Люди, 2019 год, используйте движки, умерьте убийство своего здоровья об голый год, жизнь всё ещё не такая продолжительная, чтобы сделать даже штук 20 приличных игр, за которые почти не будет стыдно.

15
Ответить

А что, если просто не нравится копаться в абсолютном чужой для тебя логике и расставлять всё мышкой в редакторе, если тебе привычнее полный контроль и код?

1
Ответить

Как будто создание 2D-движка прям такое неподъёмное и сложное для одиночки.
Как будто использование готового движка избавляет от необходимости создавать с нуля ассеты (а это, как ни крути, самая большая часть работы над игрой).
Стоит ли оптимизировать то, что и так не отнимает много времени, жертвуя при этом контролем и нормальной кроссплатформенностью?

Ну и напоследок:
Сколько коммерческих проектов написано с помощью Godot? Можете назвать хотя бы пяток приличных игр, добравшихся хотя бы до стима (чёрт с ними, с другими платформами).

2
Ответить

Можно в двух словах, зачем юзать что-то из вышеназванного когда есть Unity почти без костылей и поддержку которой девичья воля майкрософт точно не прикажет долго жить?

5
Ответить

Комментарий недоступен

5
Ответить

Лично мне не нравится изучать чужой инструмент с нуля. Ещё и мышкой в редакторе расставлять. Куда ближе самому, ручками всё кодить.

2
Ответить