В данной статье будет рассказана история разработки одной мобильной игры. Также будут освещены следующие вопросы:  Стоит ли использовать jQuery? Стоит ли вообще разрабатывать мобильные игры на JS с нуля? Итак, прежде чем начать говорить о разработке, следует немного рассказать следующее:    Как вообще появилась идея разработки мобильной игры? Почему были выбраны эти инструменты для разработки? Почему не стоит делать так же? С чего все началось? Учебный год в университете подходил к концу, студенты закрывали сессии и долги, а также думали о том, как бы пополнить портфолио и подать на стипендию. Я не был исключением и как раз смог устроиться в один международный проект. Работа заключалась в верстке сайта, переносе и настройке его под WordPress. К сожалению, одного проекта было недостаточно и как раз проводился международный конкурс. Это был шанс получить ценный опыт и возможность занять призовое место. Номинации были в различных сферах: машинное обучение, 1С, мобильная разработка, Big Data и др. Из всех конкурсов был выбран конкурс «веб-дизайн». Необходимо было продумать и разработать два макета по заданным требованиям, один для мобильных устройств и один для десктопа. Мои товарищи и одногруппники выразили желание поучаствовать в конкурсе и вместе мы записались на конкурс «мобильная разработка». Сначала я пытался везде успеть, но, к сожалению, успеть везде было крайне сложно и в итоге было принято решение сделать упор на командном конкурсе по мобильной разработке. Команда была крайне ответственной и поэтому собраться и поработать не составляло проблем, однако возникла другая проблема: все мы работали с разными технологиями. В итоге у нас была команда из Java, Python и JS-разработчиков. Причем каждый из нас только постигал инструменты и был в состоянии поиска себя как программиста. Я бы сказал, что наш уровень был «Junior--» 😊.  На конкурс было отведено 4 недели, первую неделю мы занимались учебой и важными делами. Вторую неделю мы выбирали, что и как мы будем делать. Было много различных идей, но в итоге пришли к тому, что надо попробовать сделать мобильную игру. С учетом того, что в конкурсе участвовало 140 команд от 1 до 4 человек, было принято решение сделать упор на дизайн. Мы, люди, оцениваем в первую очередь внешний вид, причем как людей, так и всего остального. Я убежден в том, что о дизайне нужно заботиться в первую очередь. На теме дизайна и его влияния останавливаться не будем, возможно, на эту тему будет отдельная статья. Нужно было придумать, что наша команда будет разрабатывать, и тут я вспомнил, что хотел когда-то сделать игру про алхимию, где нужно собирать ингредиенты, убивать мобов, прокачивать персонажа и т.д. В старых файлах на компьютере нашлись кое-какие материалы по данной теме, иконки и некоторые наработки. Но их было слишком мало, и потому всю неделю мы занимались поиском иконок и материалов, которые можно было бы использовать, не покупая лицензий. В итоге собрали всяких продуктов, склянок, зелий и прочего. Далее наша команда занялась проектированием и распределила задачи по важности: Затем дорисовали ресурсы, сделали рамки и поделили их по качеству: В итоге получилось 70+ зелий и 150+ ресурсов. Мы продумали для зелий схемы смешивания, после чего занялись интерфейсом. Особо опыта ни у кого не было, но мы постарались как могли, и в итоге был получен следующий дизайн: Выбор инструментов разработки Итак, пришло время обсудить инструменты для разработки. Изначально было много всяких вариантов – Gdevelop, Construct, PixiJS, PhaserJS и т.п. Оставалось всего две недели, мы посмотрели некоторые из вышеописанных библиотек и пришли к выводу, что разбираться с ними времени нет. Нам нужен был полный контроль и возможность реализовать всё так, как было в разработанном нами дизайне, потому придумывать ничего не стали и решили использовать старый добрый JavaScript. Приложение достаточно простое, поэтому мы решили сделать его в виде сайта, то есть использовать HTML и CSS для верстки, JS для написания логики, а также Apache Cordova для того, чтобы упаковать всё в apk-файл. С продукцией Apple никто особо знаком не был, потому лезть туда даже не стали. Также подключили Firebase для хранения данных пользователей и jQuery, чтобы было удобнее делать всякие всплывашки, переходы и т.п. В итоге стек был следующий: HTML, CSS – верстка; JavaScript – логика приложения; jQuery – придание интерактивности интерфейсу; Firebase – БД для хранения данных пользователя; Apache Cordova – система сборки итогового APK-файла. Стоит ли использовать jQuery? Для некоторых это, возможно, спорный вопрос, но для меня ответ очевиден: нет, не стоит. Конечно, если вы поддерживаете старый проект с jQuery, то, само собой, не стоит все переписывать на JS. Однако если вы разрабатываете проекты с нуля, то стоит задуматься об использовании нативного JS. Во-первых, вы будете больше практиковаться и чувствовать себя комфортнее, если вам нужно будет дорабатывать проекты на нативном JS, во-вторых, если jQuery «умрет», то с JS такое вряд ли случится, поэтому с навыками JS вы сможете при надобности быстро изучить любую библиотеку. Этот ответ может показаться очевидным, однако я до сих пор замечаю, как люди используют данную библиотеку, при этом отказываясь изучать JS. При этом изучать нужно в первую очередь именно JS, потому что все библиотеки написаны на нем, и если знать сам язык, то разобраться в новой для себя библиотеке никогда не составит труда. Процесс разработки Вот и добрались до разработки, в этом разделе будет показан программный код и почему (с точки зрения автора) он был написан именно так. На верстке и стилях останавливаться не будем и перейдем сразу к главному и единственному файлу с логикой игры. Прежде чем запускать весь код, необходимо было проверить, что устройство готово и Cordova полностью загрузилась. Для этого Apache Cordova предоставляет событие «deviceready»: Далее в callback-функцию помещаем весь остальной код. Приложение использует Firebase и для его работы необходимо описать config со всеми данными. Также инициализируем локальное хранилище (Local Storage), в него будут помещаться все изменения, а при выходе из приложения будет осуществляться сохранение уже в базу данных, тем самым позволяя уменьшить количество запросов на сервер: Как видно, при событии «pause» вызывается функция «saveGame». Данная функция отвечает за сохранение данных в Local Storage. Событие «pause» предоставляет Cordova, и срабатывает оно в момент сворачивания приложения, а точнее, когда приложения переходит в фоновый режим. Далее рассмотрим главный объект «gameState» со всеми параметрами: Тут должно быть все более-менее понятно, а вот дальше уже пойдут страшные вещи.  Рассмотрим методы объекта «gameState». Честно говоря, я не помню логическую последовательность созданных методов 😊, поэтому пойдем сверху вниз. Первый метод реализует продажу предметов: Данный метод получает id предмета и его количество (подразумевается, что можно продать как 1 ед., так и всё сразу). В игре это выглядело следующим образом: Далее достаем элемент из инвентаря и сравниваем его количество с переданным количеством на продажу, затем уменьшаем на переданное количество, прибавляем деньги, обновляем поле в HTML и вызываем метод обновления инвентаря. Если с методом по «продаже» все понятно, то вот о методе «покупки» такого не скажешь: Первое, что бросается в глаза внимательному читателю – а что за itemPack? На самом деле я тоже сначала не мог понять 😊. Как оказалось, на 934 строке была загрузка предметов из базы: Догадаться разделить зелья и ингредиенты по отдельным таблицам было невероятно сложно (сарказм 😊), и потому есть странный цикл, который подсчитывает, что из всего лежащего является зельем (если есть свойство components у элемента, то это зелье) Странно, никто даже не додумался ввести поле «тип» и дальше по нему определять тип предмета (ингредиент/зелье). Количество рецептов («recMax») мы подсчитывали для того, чтобы отобразить сколько всего зелий можно открыть: Думаю, многие уже поняли, что так лучше не делать, к чему эти лишние циклы ведь можно просто вынести все элементы в отдельную таблицу и просто подсчитать сколько там элементов или добавить тип, по которому можно определить тот или иной элемент и т.д. Вернемся к методу «buyItem», с «fItem» все понятно: достаем элемент из общего массива предметов, далее создаем новый объект item с дополнительным свойством count для того, чтобы туда можно было записать количество предмета (они могут объединяться в пачку). Далее нужно найти элемент в инвентаре, чтобы объединить предметы в одну пачку, если предмет уже есть. Ух, перейдем к условиям: В первом условии проверяем, хватает ли денег, и если не хватает, то показываем сообщение с ошибкой. Во втором условии проверяем, есть ли уже покупаемый предмет в инвентаре и хватает ли места в инвентаре, если нет, то показываем сообщение, что нет места. Если место есть, то объединяем предметы в одну пачку и проверяем, не переполнился ли инвентарь, и если переполнился, то откатываемся обратно. Если место есть, то отнимаем деньги, обновляем отображение и выводим сообщение, что товар добавлен. Далее проверяем, кратно ли количество элементов в пачке пяти, если да, то закидываем сгенерированный HTML в инвентарь, если нет, то ищем все изображения внутри инвентаря, а затем берем номер изображения и сравниваем с id элемента, после чего у span удаляем класс hidden, который скрывал количество предметов: Не спрашивайте, почему всё так плохо, я и сам сейчас не понимаю 😊. Ну, и заключительное условие уже просто проверяет есть ли место в инвентаре и если есть, то добавляет предмет. Чтобы вы понимали масштабы, мы рассмотрели только 200 строк кода, а дальше еще чуть больше 1000 строк кода такого же формата, где-то лучше, где-то даже хуже. В итоге за 2 недели мы достигли следующего результата: Заключение В данной статье я постарался показать вам, насколько все плохо внутри и якобы хорошо снаружи можно сделать. Если вы помните, то проект создавался для конкурса, в котором участвовало 140 команд. Чтобы пройти отборочный этап, нужно было попасть в топ-30 команд. И как вы думаете, смогли мы попасть в топ-50 или хотя бы в топ-100? Конечно 😊, смогли, и, более того, мы были на 27 месте по результатам отборочных испытаний. К сожалению, доработать проект было уже нельзя, поэтому мы сосредоточили свои силы на презентации и выступлении. По итогам финала мы были на 9 месте, и это с учетом того, что все, кто был выше нас, либо уже зарабатывали на своих приложениях, либо имели хорошие возможности для заработка. Конечно же, на это повлияло множество факторов: выступление, презентация, внешний вид конечного продукта. Если оценивать только код, то, конечно, мы и не поднялись бы дальше 100го места. Ну, и в заключение отвечу на вопрос: стоит ли вообще разрабатывать мобильные игры с нуля? Конечно же, невозможно просто ответить в двух словах, на это влияет множество факторов и на эту тему можно написать отдельную большую статью. В сторону геймдева лезть не будем, но все же можно дать следующие рекомендации: Определите размер и сложность своей игры. Если вы хотите сделать 2D/3D RPG с большим количеством динамики, анимации и т.п., при этом вы знаете, скажем, только один язык программирования, то следует поискать и изучить инструменты для создания игр, анимации на этом языке. Продумайте структуру проекта. Если вы решили использовать JS, то сразу продумайте структуру, разделите все на компоненты, вынесите логику и отрисовку в отдельные файлы. Не жалейте на это времени, в дальнейшем вы будете себе благодарны, и, вернувшись к проекту через какое-то время, вы не будете тратить недели, чтобы понять, что и как там происходит. Займитесь планированием. Потратьте время на планирование проекта, в противном случае вам придется додумывать на ходу, а это всегда плохо. И настанет момент, когда это «додумывание» превратится в «ладно, пусть будет пока так, а потом додумаю» (знакомо, да?! 😊). Ну, собственно, на этом всё. Сейчас эта версия проекта убрана в ящик истории, и идеи, которые лежали в ее основе, были использованы для нового проекта, в ходе разработки которого я стараюсь учитывать все ошибки и недочеты, часть из которых я изложил в этой статье. Цель же написания этой статьи состоит в том, чтобы показать, что, если у вас есть идея и желание воплотить ее, но пока нет соответствующих навыков, никогда не стоит бояться хотя бы попытаться претворить ее в жизнь. Ошибки, недочеты и неоптимальные решения неизбежны, но все они в конечном счете станут тем ценным опытом, который поможет вам идти дальше, расти над собой, повышать свою квалификацию, а также в конце получать радость выполненной работы. Также хочется выразить огромную благодарность моему товарищу Александру Леонову который не пожалел времени и сил, чтобы отредактировать данную статью и исправить недочеты. Разрабатывайте, господа, разрабатывайте чаще! Front-End Developer