Kotlin и стоимость разработки игры (+ немного оффтопика)
Добрый день. Сегодня я хочу рассказать о разработке игры с использованием языка программирования Kotlin. Также приведу небольшой пример работы с RxJava в конце статьи.
Первый commit для этой игры случился 4 июня сего года, то есть до открытой беты я дошёл примерно за 3 с половиной 4 недели. Нельзя сказать что это первая игра или программа под Android которую я разрабатываю, но и опытным разработчикам под Андроид я также не являюсь. Мой предыдущий опыт в основном составляла Enterprise разработка.
Я хочу обозначить несколько тем в этой статье и пробежаться по ним коротенечко. Тему Kotlin’a постараюсь раскрыть подробно, по остальным возможны дополнительные статьи если будет такой запрос от вас (ну и плюс уточняющие вопросы в комментариях помогут улучшить подачу материала). Итак к списку: это сравнение стоимости разработка на Kotlin vs Java, где брать графику для вашей игры. Немного про деньги (пока про затраты, т.к. статистики по доходам пока нет). Также я считаю очень важно коснуться мотивировочной части. Начнем пожалуй с конца.
Почему я начинаю эту статью с такой казалось бы мелочи как мотивация? Ведь если я хочу создать приложение, значит я уже мотивирован. И всё хорошо, и меня ждет успех. Проблема в том что часто приступая к работе мы не осознаем свою истинную мотивацию: ждем ли мы денег, есть ли личная потребность, хотим ли мы создать пример для своего портфолио. Вариантов может быть много. Казалось бы, какая разница если я все равно мотивирован? Но взять к примеру портфолио — вроде бы хорошая инвестиция. Ты сможешь показывать своим потенциальным работодателям готовый продукт и они конечно же впечатлятся и тут же назначат огромную зарплату. Так вот, по мере разработки, по мере того как вы вкладываете свои силы и время, ценность портфолио начинает отходить на второй план (особенно если визуальной привлекательности добиться не удается). Уже хочется получить каких-то денег и если изначально планов монетизации приложения не было, то каждый следующий день требует все большей силы воли. Так в чём же проблема? Казалось бы — начинал работать с одной мотивацией, а в середине процесса разработки добавил монетизацию, выложил в Google Play и заработал 100500 руб. К сожалению так не работает. Пользователи не хотят тратить время на глючное, сырое или неинтересное приложение. То есть вы не можете выложить проект в середине разработки. Если вы так сделаете, скорее всего это просто приведет к падению рейтинга и отсутствию скачивания. То есть вся ваша работа по сути уйдёт в мусорную корзину.
Если вы изначально рассматриваете монетизацию как один из своих интересов, еще до самого старта работ вы должны понимать на чём вы будете зарабатывать деньги. Самое простое и самое неэффективное это рекламные баннеры. Чуть сложнее или примерно так же просто — показ рекламы на весь экран. Далее идет магазин. Но для того чтобы магазин заработал, вам необходимо зацепить пользователя чем-то. Чем раньше вы получите просмотр рекламы, тем больше это будет подпитывать вашу мотивацию продолжать работать дальше.
Вопрос графики для программиста является пожалуй что основной проблемой. Я имею в виду игры конечно. Когда я только начинал разработку, я считал что главное написать код, а уж найти графику не такая большая проблема. Может быть даже и заказать.
Существует значительное количество стоков ресурсов где графика продается, существуют ресурсы с бесплатными картинками. И в принципе да, действительно, так оно и есть. Есть только одна проблема — эти ресурсы выполнены в разных художественном стиле и комбинация из них даёт крайне странные результаты. Поэтому если вы разрабатываете свою первую игру, мой вам настоятельный совет — не ищите графику под свои задумки. Ищите готовые наборы графики под игру, и исходя из графики решайте что вы можете реализовать. Такие наборы есть, их не так чтобы много, но по крайней мере для первого второго раза вам хватит.
В моем же случае получилось что я потратил 2 недели на разработку, купил какие-то ресурсы в маркетах, но естественно их не хватило для того чтобы реализовать мою задумку. Скажу честно — купленная графика составляла менее чем 30% от необходимого. Но ведь нет нерешаемых вопросов, можно найти исполнителей которые нарисуют то, что вам нужно. И здесь мы с удивлением узнаём, что это не так просто. Особенно если нас интересует качественный результат. Что делал я — я просматривал стоки, находил интересные в плане графики экземпляры, переходил на описание автора и пробовал связаться.
Уже на этом этапе у вас должен быть перечень элементов которые вы хотите заказать и уже на этом этапе скорее всего ваши розовые слоники приопустят хоботы. Но пока это только предчувствие. Вы отправляете письмо с вопросом “можно ли обратиться для заказа графики” и в зависимости от профессионализма исполнителя (а те люди с которыми я обращался были профессионалами за исключением одного) вы получите сразу ответ что “Да можно, часовая ставка 25$/час”, ваш запрос будет выполнен за 30-40 часов не включая доработки по замечаниям (свободное время для заказа будет через полтора месяца). Или “Могу сделать за месяц-полтора, будет стоить 50 тысяч рублей”. Либо “Нет, у меня я слишком много работы и я дополнительные заказ не беру”. Это всё профессиональный варианты ответа. А самое неудачное что со мной случилось это следующее:
— А сколько вы готовы заплатить? (То есть человек не оценивает ресурсоемкость или сложность поставленной задачи, а пытается адаптироваться под платежеспособность заказчика)
— от 10000 до 20000 руб (Это был первый художник с которым я связался и в тот момент я считал что данная сумма Вполне себе подходит для небольшой, как я считал, работы)
Человек большого интереса не проявил, на вроде как согласился. Сам назначил срок когда даст описание что он за эту сумму может мне предоставить… и пропал. Это даже не звоночек это колокол что дальнейшая работа с подобным человеком для вас закончится неудачей. Тем не менее через 3 дня после озвученного им же срока, он связался со мной и сказал что сделает всё что мне надо за 15000 рублей. Я очень настороженно отношусь к обобщениям, поэтому попросил перечислить что же будет входить в это “всё” по пунктам. После чего человек пропадает с концами и я считаю что это счастливый конец истории.
Kotlin
Разработка личного проекта существенно отличается от рабочего. Различий несколько, но я остановлюсь на самом (для меня) существенном. Это отношение к стоимости разработки. В подавляющем большинстве случаев работодатель определяет требования, часто инструмент. Он же несет финансовую ответственность. Есть тестирование или нет, какие библиотеки и какой стек технологий. В личном проекте все права и все обязанности — на вас лично. Хотите использовать новый фреймворк — ради бога. Но время которое вы потратите на его освоение вы будете “оплачивать” из своего кармана. И да, не стоит думать что вы работаете бесплатно. Выкиньте из головы эту мысль, напишите на стикере вашу ставку в час и крайне желательно чтобы она соответствовала хотя бы средней стоимости специалиста вашей квалификации по городу. Не надо занижать себе цену.
Таким образом вопрос эффективности вашей работы встает на первый план. А сделал ли я что-то полезное за эти 8 часов, за что в ином случае я получил бы (к примеру) 4000 рублей? То есть вопрос Kotlin vs Java я предлагаю решать исключительно с финансовой точки зрения. Оба языка тьюринг-полные и значит любую программу написанную на Kotlin можно реализовать на Java и наоборот. За счет чего же мы можем получить разницу в стоимости разработки/стоимости владения продуктом?
Стоимость разработки — это количество денег для реализации функциональности. Стоимость владения = стоимость разработки + стоимость поддержки. В некоторых случая стоимость поддержки несоизмеримо выше стоимости разработки. Это особенно характерно для write-only языков (пример RegExp. Гораздо проще написать новое выражение чем понять где ошибка в существующем).
В идеале язык должен быть дешевым и в разработке, и в поддержке. Сокращение boilerplate code однозначно удешевляет разработку. Синтаксический сахар удешевляет разработку, но может (подчеркну может, но не обязан) приводить к увеличению стоимости владения. Синтаксическая соль удорожает разработку но удешевляет стоимость владения. Ниже я приведу примеры кода на Kotlin и Java и опишу какой вариант на мой взгляд дешевле и почему. Часть примеров будет из моего проекта, часть нет.
* Для DTO классов нет необходимости в геттерах/сеттерах
** Геттеры/сеттеры имеют смысл только и только в том случае, если они меняют поведение при работе с полями
В данном сравнении мы видим что код на Kotlin более читаемый и самое главное он защищен от “ошибки на миллиард” — NPE. И id, и speed в Kotlin не могут быть null.
Второй, не менее важный момент в приведенном выше примере — это мутабельность.
Не так много разницы, не правда ли? Тем не менее модификаторы final смотрятся крайне неуместно и визуально засоряют программу. Это приводит к тому, что final используется в Java гораздо реже чем следовало бы. А ведь иммьютбл гораздо дешевле и в разработке и во владении.
А вот пример трансформации данных:
Тут два момента. Kotlin выполняется на jvm 6, Java требует jvm 8 для стримов. А для андроида, это на минуточку 24 API. На 5 июня это всего 9,5% устройств. И второй момент — final or effectively final переменные в лямбдах Java.
Инициализация объекта в Kotlin’e возможна в одном месте что сокращает контекст для программиста и снижает стоимость вложения
В принципе, из того что я попробовал в Kotlin это самые серьезные вещи, влияющие на стоимость владения продуктом. Я сейчас не хочу говорить про вкусовщину типа data classes, перегрузку операторов, string template, lazy properties и т.п. Все это вещи интересные но они могут как сокращать, так и увеличивать стоимость владения.
В заключение небольшой пример Kotlin + RxJava + Jackson. Я хочу иметь dto класс, который позволит не просто хранить данные, но и уведомлять об их изменениях. Пример упрощенный для более наглядной демонстрации.
Здесь хочу обратить внимание на перегрузку val rx. При подписке на Observable сразу же приходит текущее значение. Это важно т.к. десериализация из json’a случается раньше чем верстка экрана и подвязывание графических элементов к свойству. А при startWith мы сразу инициализируем графический элемент текущим значением и меняем по ходу пьесы.
Класс Car прекрасно сериализуется/десериализуется Jackson’ом, может быть использован как классический dto класс, но в то же время позволяет обрабатывать изменения свойств в реактив стиле.
Ниже пример подвязки Label к свойству объекта:
К сожалению я не могу представить объективных цифр насколько стоимость владения продуктом на Kotlin’e дешевле Java. Да и само это утверждения я уверен будет не раз оспорено в комментариях. Могу сказать только по своему субъективному суждению, цифра в 1.5 — 2 раза для меня реальна. Причем сокращение стоимости владения в полтора раза характерно для начала перехода с Java на Kotlin, примерно через неделю-две я думаю на двойную эффективность вышел. В основном за счет NPE-proof, immutable, lambda & функции высшего порядка.
Создаём своё первое приложение для Kotlin Multiplatform
ведущий мобильный разработчик компании Usetech
Основная идея KMP, как и других кросс-платформенных SDK — оптимизация разработки путем написания кода один раз и последующего его использования на разных платформах.
Согласно концепции JetBrains, Kotlin Multiplatform не является фреймворком. Это именно SDK, который позволяет создавать модули с общим кодом, подключаемые к нативным приложениям.
Написанный на Kotlin модуль компилируется в JVM байткод для Android и LLVM байткод для iOS.
Этот модуль (Shared, Common) содержит переиспользуемую бизнес-логику. Платформенные модули iOS/Android, к которым подключен Shared/Common, либо используют написанную логику напрямую, либо имплементируют свою реализацию в зависимости от особенностей платформы.
Общая бизнес-логика может включать в себя:
Также в нее могут входить архитектурные компоненты приложения, напрямую не включающие UI, но с ним взаимодействующие:
Концепцию Kotlin Multiplatform можно сравнить с реализацией Xamarin Native. Однако, в KMP нет модулей или функционала, реализующих UI. Эта логическая нагрузка ложится на подключенные нативные проекты.
Рассмотрим подход на практике и попробуем написать наше первое приложение Kotlin Multiplatform.
Для начала нам потребуется установить и настроить инструменты:
Мы рассмотрим создание проекта с помощью Intelij IDEA.
Выбираем меню File → New → Create Project:
В появившемся окне выбираем тип проекта Kotlin → Mobile Android/iOS|Gradle
Далее стандартно задаем путь к JDK, имя и расположение проекта
После нажатия кнопки Finish проект сгенерируется и будет почти готов к работе.
Рассмотрим, что у нас получилось:
Мультиплатформенные проекты Kotlin обычно делятся на несколько модулей:
В них располагается наша бизнес-логика. Сам код базового примера мы разберем немного позже.
Код нативного Android приложения располагается в каталоге main, как если бы мы создавали проект по шаблону обычного Android.
iOS приложение создается автоматически и располагается в каталоге iOSApp:
Перед тем, как мы проверим работоспособность базового решения, необходимо сделать следующие финальные настройки:
В local.properties зададим путь к SDK Android:
Создадим конфигурацию для работы Android приложения:
Теперь вызовем команду gradle wrapper для сборки нашего модуля общей логики:
После сборки модуль для бизнес-логики для Android приложения доступен в app/build/libs:
Путь к библиотеке прописывается стандартно, в блоке dependencies файла build.gradle:
Теперь наш проект сконфигурирован для запуска Android приложения:
Осталось сделать настройки для запуска приложения iOS.
В файле build.gradle(:app) необходимо изменить настройку архитектура проекта, чтобы наше приложение поддерживало как реальные устройства, так и эмуляторы.
После выполнения сборки создастся фреймворк в app/build/bin/ios:
Intelij IDEA автоматически создает в gradle файле код для генерации, подключения и встраивания фреймворка в IOS проект:
При ручной настройке проекта (например, через Android Studio) этот код потребуется указать самостоятельно.
После синхронизации gradle iOS проект готов к запуску и проверке с помощью XCode.
Проверяем, что у нас получилось. Открываем проект iOS через iosApp.xcodeproj:
Проект имеет стандартную структуру, за исключением раздела app, где мы получаем доступ к коду наших модулей на Kotlin.
Фреймворк действительно подключен автоматически во всех соответствующих разделах проекта:
Запускаем проект на эмуляторе:
Теперь разберем код самого приложения на базовом примере.
Используемую в проекте бизнес-логику можно разделить на:
Переиспользуемая логика располагается в проекте commonMain в каталоге kotlin и разделяется на package. Декларации функций, классов и объектов, обязательных к переопределению, помечаются модификатором expect :
Вызов логики производится в нативном проекте:
Теперь попробуем по тем же принципам сделать что-то посложнее и поинтереснее. Например, небольшое приложение для получения и отображение списка новостей для iOS и Android.
Приложение будет иметь следующую структуру:
В общей части (Common) расположим бизнес-логику:
В модулях iOS/Android приложений оставим только UI компоненты для отображения списка и адаптеры. iOS часть будет написана на Swift, Android – на Kotlin. Здесь в плане работы не будет ничего нового.
Организуем архитектуру приложений по простому паттерну MVP. Презентер, обращающийся к бизнес-логике, также вынесем в Common часть. Также поступим и с протоколом для связи между презентером и экранами UI:
Начнем с бизнес-логики. Т.к весь функционал будет в модуле common, то мы будем использовать в качестве библиотек решения для Kotlin Multiplatform:
1. Ktor – библиотека для работы с сетью и сериализации.
В build.gradle (:app) пропишем следующие зависимости:
Также добавим поддержку плагина сериализации:
2. Kotlin Coroutines – для организации многопоточной работы.
При добавлении зависимости в iOS проект обратите внимание, что версия библиотеки должна быть обязательно native-mt и совместима с версией плагина Kotlin multiplatform.
В commonMain создадим Dispatchers.kt, где объявим переменные:
Реализация в androidMain создается легко. Для доступа к соответствующим потокам используем CoroutineDispatchers Main (UI поток) и Default (стандартный для Coroutine ):
С iOS труднее. Та версия Kotlin Native LLVM компилятора, которая используется в Kotlin Multiplatform, не поддерживает background очереди. Это давно известная проблема, которая к сожалению, еще не исправлена
Поэтому попробуем обходной маневр как временное решение проблемы.
Также нам понадобится свой scope для работы сетевого клиента:
Android
Применим это при реализации сетевого клиента на Ktor:
Вызывать бизнес-логику будем в презентере. Для полноценной работы с coroutines нам надо будет создать scope:
и добавить его в презентер. Вынесем в базовый класс:
Теперь создадим презентер NewsListPresenter для нашего модуля. В инициализатор передадим defaultDispatcher :
Обратите внимание! Из-за особенностей текущей работы Kotlin Native с многопоточностью в IOS работа с синглтонами может привести к крашу. Поэтому для корректной работы надо добавить аннотацию @ThreadLocal для используемого объекта:
Осталось подключить логику к нативным IOS и Android модулям и обработать ответ от Presenter:
Запускаем сборку common модуля gradle wrapper, чтобы сборки обновились. Проверяем работу приложений:
Готово. Вы великолепны.
Оба наши приложения работают и работают одинаково.
Информационные материалы, которые использовались:
LibGDX + Scene2d (программируем на Kotlin). Часть 0
И снова всем привет! Спешу поделиться, у меня были отличные выходные! Полтора дня я обдумывал вариант подачи материала, пилил макет и вообще всячески старался сделать хорошо. Что такое хорошо в контексте обучающего материала? На мой взгляд это «интересность», краткость, корректность и наглядность. Для меня лично написать такую статью — это подвиг. А вот серию статей — просто емкая и ответственная задача. Изучать Scene2d мы будем в процессе написания игры с нуля! Процесс нашего творчества растянется на долгие десять-двенадцать дней. Мне хочется верить что периодичность материалов будет примерно раз в день. Для меня лично это очень амбициозная задача, ведь требуется не столько запрограммировать, но и описать в статьях с детальным разбором. Я не сторонник бросаться в бушующий океан, в надежде научиться плавать. Мы прыгнем у лужу и будем последовательно ее углублять и расширять. Итак начинаем.
Разработку любой программы я настоятельно советую начинать с составления карточки продукта. Из обязательного — цели. Я составляю карточку продукта в Google Docs и вот как карточка выглядит в нашем случае.
Средневековый магнат
Цели проекта
Игровой мир
Средние века / фэнтези
Цель игры — много денег
Сбор ресурсов
Продажа
Описание процесса игры
Так как первая и основная цель данной разработки является демонстрация работы, и игровой мир, и описание игрового процесса будут упрощены в угоду краткости и ясности подачи материала.
Игрок собирает ресурсы и продает их на местном рынке. На поиск и сбор ресурсов тратится еда/энергия. Когда энергия кончилась, ее необходимо покупать в городе.
Прототип интерфейса
Несмотря на то, что в предыдущей статье я рекомендовал тетрадку и карандаш в качестве инструментов для прототипирования, этот макет сделан в Adobe Experience Design CC (Beta). На момент публикации статьи, его можно скачать бесплатно. На работу с ним я угрохал полтора дня но считаю это оправданным. Дело в том, что публикация на Хабре является групповой работой, даже если я все делаю один. Чем более качественные опорные материалы я предоставлю, тем легче будет воспринимать информацию. Вот проектный файл Adobe Experience Design. Его можно скачать, запустить в режиме презентации и даже немного потыкать по кнопкам. Технически можно запилить отдельную статейку, но не знаю нужно ли это. Комментарии рассудят.
Ну и какая разработка без публичного репозитория? Вот ссылка.
Для работы нам понадобится Android Studio 3.0 (на данный момент доступна версия Canary 5), Android SKD и LibGDX. Установку всех этих тряхомудрий я пропущу, тут все большие мальчики и девочки. На крайний случай есть комментарии.
Запуск мастера конфигурирования LibGDX происходит из командной строки:
Кто был не в курсе, LibGDX это кроссплатформенный фреймворк, позволяющий писать одновременно под PC, Android, iOS и даже HTML (для последнего используется GWT, а у нас Kotlin, так что HTML нам точно не грозит). Из расширений я выбрал два:
Freetype — позволяет генерировать растровые шрифты из ttf/otf
Tools — среди прочего позволяет генерировать атласы текстур
Коммит с получившимся проектом доступен в репозитории. Я старался крошить и именовать коммиты таким образом, чтобы было просто понять какой фрагмент за что отвечает. Так как LibGDX кроссплатформенный, я предпочитаю большую часть разработки проводить на PC и тестировать/исправлять ошибки под Android непосредственно перед релизом. Как правило на эту работу уходит не больше 2-3 часов времени.
Дальше в этой статье
Запуск проекта через DesktopLauncher
Обратите внимание, что рабочая папка для DesktopLauncher расположена в android/assets. Запуск DesktopLauncher на коммите:
Обратите внимание, что даже только что сконфигурированный проект не запускается под android. Мы поправим это на следующем шаге.
Перевод проекта на Kotlin
LibGDX проекты сконфигурированы как мультимодульный gradle. Есть проектный build.gradle и модульные build.gradle для core, android и desktop. Почти весь код мы будем писать в core. В проекте android позже у нас будет сидеть AdMob + конфигурация immersive mode + покупки в Google Play маркете.
Для перевода проекта из java в kotlin мы меняем все apply plugin: «java» на apply plugin: «kotlin». В android/build.gradle добавляем apply plugin: ‘kotlin-android’. Самые большие изменения произошли в проектном build.gradle
Добавился гугловый репозиторий, в buildscript.dependencies добавлен kotlin-gradle-plugin и в core проект добавлена compile-зависимость kotlin-stdlib (в нашем случае kotlin-stdlib-jre8).
Данная версия работает на android, но не работает в desktop варианте из-за ошибки Android Studio 3.0 Canary 5. Почему я считаю что это причина — запуск gradle цели desktop-run таки запускает приложение (правда требует запущенное Android device/emulator для запуска android:run). А вот запуск из Android Studio выкидывает Exception in thread «main» java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics. Если кто сможет победить запуск DesktopLauncher’a со свежей версией gradle — дайте знать пожалуйста!
Перевод java файлов в kt элементарна — выделяете файл/папку и жмете Ctrl+Alt+Shitf+K. Единственная ошибка которая возникнет у вас после данной операции заключается в требовании Kotlin’a инициализировать свойство в момент определения:
internal = package видимость в java. Нам пакетная видимость не нужна (и вообще через пару коммитов мы удалим эти поля). Не во всех случаях мы можем проинициализировать поле сразу, а делать его nullable это вообще глупость (нам котлин интересен как раз из-за null-safety). Для этого в kotlin есть модификатор lateinit, который говорит компилятору, что программист зуб дает, на момент использования этого поля оно не будет равно null. Это так называемая синтаксическая соль. Вообще, если смотреть на этот код не как результат автоматической конверсии, то уместнее бы смотрелось:
Ошибка Kotlin not configured
Эту ошибку вы будете видеть каждый раз при запуске Android Studio. Просто щелкните синхронизировать gradle:
Конфигурация gradle для kotlin-desktop версии
Как я уже говорил, я предпочитаю разрабатывать desktop версию приложения, и изменением пары строчек мы реанимируем этот режим. Все что нужно — указать в проектном build.gradle
classpath ‘com.android.tools.build:gradle:2.3.2’, а в gradle-wrapper.properties версию gradle-3.3-all.zip
Конфигурация портретной ориентации для desktop версии
В DesktopLauncher добавляем горсть параметров конфигурации. Три относятся к размеру окна и возможности изменения размеров. Четвертый параметр vSync отключен т.к. есть глюк, на некоторых видеокартах в desktop и только на config.foregroundFPS=60 (по умолчанию), грузит одно ядро процессора в 100%.
Первое использование Scene2D. Загрузочный экран, загрузочная сцена
Вот мы и добрались до первого использования Scene2D. Коротко пару слов для чего он предназначен и что можно от него хотеть.
Scene2D является графом (деревом) элементов и предназначен в первую очередь для создания UI. Прямо «из коробки», вы получаете возможность верстки, трансформации элементов (поворот, масштаб, сдвиг и т.д.). Огромным плюсом идет обработка касаний. Ну и вишенка на торте система действий. С непонятным определением закончили, теперь то же самое человеческим языком.
Есть сцена, она занимает весь экран. На сцене вы можете разместить таблицу, в таблице картинку, панель прокрутки, десяток кнопок и даже черта лысого (главное чтобы в душе он был Actor’ом). При помощи волшебных слов top/center/left/width и т.д. вы реализуете верстку. Пример сложнее чем hello world будет только завтра, и так статья большая получилась. Дальше на любой произвольный элемент вы вешаете обработчик касания и он работает. Вам не нужно вручную ловить координаты клика, проверять что же находится там, какой у объектов z-index и т.п. Но еще раз, про это завтра. А сегодня просто несколько фрагментов кода напоследок:
Наш класс MedievalTycoonGame теперь наследуется от Game, вся задача которого свалить работу на Screen. Первый экран, который мы сейчас покажем пользователю будет называться LoadingScreen и будет содержать одну сцену — LoadingStage. Т.к. не предполагается разрастания этих классов, я размещу их в одном файле LoadingScreen.kt
Все что делает LoadingScreen — затирает экран черным цветом и вызывает методы act() и draw() у LoadingStage. На act() очень удобно вешать логику программы, работу с данными. Draw() это просто отрисовка всех элементов сцены.
Единственный момент, хочу заакцентировать как выглядит инициализация сцены java vs kotlin
В случае с kotlin у нас всегда инициализация элемента и его размещение на соседних строчках. Это достигается за счет функции расширения apply. Иерархия в kotlin автоматически создает отступы и визуально очень легко читается. В java вся верстка идет без отступов. Инициализация элемента и его размещение часто невозможно рядом. Если иерархия состоит из 3+ уровней глубины, упорядочить элементы красиво (и дешево в поддержке) в java невозможно.
На сегодня это все. Рассматривайте эту статью как вводную, собственно раскрытие Scene2D и реализация игры будет завтра и далее. Спасибо что были с нами 😉 И не рекламы ради (в этом приложении надо приложить усилия чтобы увидеть рекламу), мой первый проект «Пятнашки» на Scene2D когда я еще только-только осваивал. Из достоинств — удобство управления. Существуют сотни если не тысячи версий приложения и в 90% что я видел передвижение фишек возможно только тычком в соседнюю с пустой клеткой. Попробуйте собрать котика.
В следующих статьях
Upd:
ссылка на исходники Пятнашек