- PVSM.RU - https://www.pvsm.ru -
Создание игры процесс захватывающий и познавательный. Особенно это заметно, когда ремейк «классики» делаешь сам, руководствуясь идеями оригинала и десятками часов, потраченных на прохождение кампании. У меня не было сколь-нибудь значимого опыта разработки для Android'a, поэтому создание работающего «как надо» приложения для планшета поначалу выглядело довольно туманно, но от этого не менее притягательно. При наличии времени и возможностей, можно стряхнуть пыль со старых игр, подмазать и подклеить, добавив поддержку «больших» разрешений и окажется, что они выглядят не хуже современных продуктов, выложенных на маркете, даже с палитрой RGB565 без альфа-канала. Я предполагал, что будут подводные камни и заботливо спрятанные грабли, которые лежат тихонько во время разработки, но больно лупят по голове, стоит запустить игру на реальном железе. Чего сильно не хватало, так это отладчика, а возникающие проблемы лишь укрепили желание достичь поставленной цели. Под катом будет рассказ о том, как это все заработало.
Стоит сразу предупредить, что это возможно будет рассказ о велосипедах, я не придумал ничего такого, что не гуглится на просторах «интернетов». Также Читатель вряд ли увидит новые решения или мега технологии, но найдет опробованные инструкции по сборке приложения, использующего SDL1/2, для Android.
Здравствуйте!
Ремейк игры Caesar III© [1] начинался совсем не как отдельный проект, а скорее набор фиксов для количества жителей, поддержки «больших» разрешений и исследования декомпилированного кода оригинальной игры [2] в поисках пасхалок и недокументированных режимов работы. А когда количество восстановленного кода перевалило за половину от общего, стало понятно, что можно попытаться восстановить игру. В качестве библиотеки отрисовки была выбрана SDL1.2, которая хорошо зарекомендовала себя в других проектах, а ещё проста в освоении и использовании. Ремейк поначалу был Linux-only, в начале этого года перебрался на другие платформы (Mac, Windows и Haiku), а потом у меня завелся вот такой планшет [3], а голове периодически возникали мысли «работает на одном линуксе, должно работать и на другом».
Попытка номер раз, удачная
У SDL версии 1.2 «из коробки» нет возможности работы под андроидом, зато есть замечательный проект libsdl-android [4], который позволяет, используя свое окружение и скрипты собирать код, использующий эту библиотеку в приложении для андроида. Собранное приложение может загрузить ресурсы как из интернета, так и распаковать из установщика. Сам libsdl-android содержит большое количество библиотек, которые могут вам понадобиться, начиная от bzip2 и разных кодеков, до самой SDL и его окружения SDL_image, SDL_mixer, ttf и другие. Если у игры нет платформозависимого кода, то портирование занимает несколько шагов:
$ keytool -genkey -v -keystore rs.keystore -alias caesaria -keyalg RSA -keysize 2048 -validity 10000
$ jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore rs.keystore ~/projects/commandergenius/project/bin/MainActivity-release-unsigned.apk caesaria
$ mv ~/projects/commandergenius/project/bin/MainActivity-release-unsigned.apk ~/projects/caesaria.apk
$ adb uninstall net.dalerank.caesaria
$ adb install ~/projects/caesaria.apk
Подводные камни
0. Определение окружения: для начала надо определиться в каком окружении будет работать Windows, Linux или Linux Android.
Решение: Проверяем наличие дефайнов ANDROID/__ANDROID__.
1. Логи: смотреть сообщения об ошибках и прочий вывод можно через abd logcat, но как оказалось стандартные средства типа stdout/printf не работают, можно конечно пользоваться выводом лога в файл и смотреть уже его, но хотелось какойто более привычной отладки.
Решение: подключаем заголовочный файл логов андроида #include <android/log.h>, а для вывода сообщения пользуемся функцией
__android_log_print(ANDROID_LOG_DEBUG, CAESARIA_PLATFORM_NAME, "%s", str.c_str() );
с привычным printf синтаксисом.
2. Использование OpenGL: если кому понадобится OpenGL, то на мобильных плафтормах обитает его близкий родственник GLES.
Решение: подключаем вместо стандартных заголовояных файлов <GLES/gl.h> и <GLES/glext.h>, есть небольшие отличия в использовани текстур и отрисовке, но в основном код(простой код, который я использовал) работает практически без изменений.
3. Обработка событий: пропадает событие SDL_MOUSEBUTTONUP при движении пальцем по экрану, это могла быть недоработка в самой библиотеке libsdl-android или я где-то его терял. Проявлялось иногда в отсутствии реакции элементов интерфейса на действия пользоватся, например после движения остановились на кнопкой, которая по идее должна перейти в состояние если над ней находится курсор мыши.
Решение: Специфично для моего приложения — при сборке под андроид было добавлено принудительное обновление состояния элементов под курсором при движении последнего.
4. Мелкий интерфейс: разрешение экрана современных мобильных устройств сопоставимо или превышает разрешение монитора, используемого 10-15 лет назад, но физические размеры заметно меньше, оттого и сам элементы пользовательского интерфейса выглядят мелко и пользоваться ими будет не всегда удобно.
Решение: Переделка интерфейса, что достаточно хлопотное занятие и не всегда удается сохранить первоначальный вид.
Один переезд равен двум пожарам(народная мудрость)
Все началось с того, что один из коммитеров прислал ссылку на ветку разработки, где успешно запустил игру с использованием относительно свежей библиотеки SDL2, а до этого использовалась версия SDL1.2 — 2008 года выпуска. Надо сказать, что я и сам рассматривал возможность перехода на новую версию, особенно после просмотра списка изменений [8], который сулил нормальную поддержку Mac и Android, что называется «из коробки». А тут еще и миниотпуск на работе получился, взяв кувалду побольше гайд потолще [9] и большую чашку кофе, я начал переводить ремейк на новый «движок».
Не хочу утомлять читателя техническими подбробностями переезда, просто у самой библиотеки с приходом аппаратной поддержки изменилась идеология работы, что поначалу доставляло определенные трудности, пока я к ней не привык. Переезд растянулся на неделю вечеров и под конец представлял собой исправление оставшихся недочетов и графических артефактов. Переделки были закончены и подготовлены сборки для «больших» ОС, и опять появилась необходимость повторного чтения мануалов по сборке приложения под Андроид, потому как libsdl-android нормально адаптирован для работы с SDL1.2, а поддержка SDL2 похоже заброшена (о чем сами авторы и пишут в ридми)
Осознал я правдивость этого текста, когда было потрачено несколько часов в попытке запустить порт в старой конфигурации через libsdl-android. Ну что ж, отрицательный опыт — тоже опыт: буду использовать доступные инструмены.
Попытка номер два, не совсем удачная
SDL2 уже содержит все необходимые конфиги для сборки прилоежния под андроид, почитав статью [10], рекомендованную на официальном сайте, можно пробовать собрать чтонибудь. Опять же будут несколько шагов, за исключением установки и настройки adt.
Для чего все эти копирования сделаны??? чтобы проще было считать относительные пути для библиотек. В папке android/libs будет лежать SDL и компания, в папке android/data — будет иконка приложения.
$ln -s ../../libs/SDL SDL
$ln -s ../../libs/SDL_mixer SDL_mixer
$ln -s ../../libs/SDL_net SDL_net
$ln -s ../../src/dep/aes aes
$ln -s ../../src/source application
$ln -s ../../src/dep/bzip2 bzip2
$ln -s ../../src/dep/freetype freetype
$ln -s ../../src/dep/libpng libpng
$ln -s ../../src/dep/lzma lzma
$ln -s ../../src/dep/smk smk
$ln -s ../../src/dep/src src
$ln -s ../../src/dep/ttf ttf
$ln -s ../../src/dep/zlib zlib
Немного о том, что же я тут написал:
zlib нужен для сборки freetype, который в свою очередь нужен для SDL_ttf и будет отвечать за рендеринг шрифтов.
Библиотека smk нужна для воспроизведния видео в формате smack, в этом формате выполнены ролики оригинальной игры.
Bzip, lzma и aes нужны для работы с zip-архивами.
libpng требуется для загрузки текстур для игры.
SDL, SDL_mixer, SDL_net отвечают соответсвено за рисования, работы со звуком и сетью.
application содержит исходники самой игры, которые будут собраны в библиотеку libapplication.so
в папке src располагаются исходники библиотеки libmain.so, а вот для неё уже написано кружево java-вызовов над с-кодом, которое позволит нам успешно стартовать и порадовать пользователя яркой картинкой.
Настройки проекта и конфиги для ndk уже любезно предоствлены авторами SDL2
Android.mk для libsmk очень прост и будет понятен людям, не связанным с программированием для андроида
#smk/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := smk
LOCAL_SRC_FILES := $(subst $(LOCAL_PATH)/,,
$(wildcard $(LOCAL_PATH)/*.c))
include $(BUILD_SHARED_LIBRARY)
Конфиг содержит указание скомпилировать все файлы с расширением .с, найденные в текущей папке (для libsmk это будет jni/smk)
Аналогично пишется и конфиг для сборки библиотеки, которая будет представлять саму игру.
#application/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := application
SDL_PATH := ../../libs/SDL
SDL_MIXER_PATH := ../../libs/SDL_mixer
SDL_NET_PATH := ../../libs/SDL_net
GAME_PATH := $(LOCAL_PATH)
DEP_PATH := ../dep
LOCAL_C_INCLUDES :=
$(LOCAL_PATH)/$(SDL_PATH)/include
$(LOCAL_PATH)/$(SDL_MIXER_PATH)
$(LOCAL_PATH)/$(SDL_NET_PATH)/include
$(LOCAL_PATH)/$(FREETYPE_PATH)/include
$(LOCAL_PATH)/$(GAME_PATH)
$(LOCAL_PATH)/$(DEP_PATH)
$(LOCAL_PATH)/$(DEP_PATH)/libpng
# Add your application source files here…
LOCAL_SRC_FILES := $(subst $(LOCAL_PATH)/,,
$(wildcard $(GAME_PATH)/*.cpp)
$(wildcard $(GAME_PATH)/core/*.cpp)
$(wildcard $(GAME_PATH)/vfs/*.cpp)
$(wildcard $(GAME_PATH)/objects/*.cpp)
$(wildcard $(GAME_PATH)/gui/*.cpp)
$(wildcard $(GAME_PATH)/city/*.cpp)
$(wildcard $(GAME_PATH)/gfx/*.cpp)
$(wildcard $(GAME_PATH)/events/*.cpp)
$(wildcard $(GAME_PATH)/world/*.cpp)
$(wildcard $(GAME_PATH)/pathway/*.cpp)
$(wildcard $(GAME_PATH)/walker/*.cpp)
$(wildcard $(GAME_PATH)/good/*.cpp)
$(wildcard $(GAME_PATH)/religion/*.cpp)
$(wildcard $(GAME_PATH)/scene/*.cpp)
$(wildcard $(GAME_PATH)/sound/*.cpp)
$(wildcard $(GAME_PATH)/game/*.cpp))
LOCAL_SHARED_LIBRARIES := SDL2 SDL2_mixer SDL2_net sdl_ttf pnggo lzma bzip2 aes smk
LOCAL_CPP_FEATURES += exceptions
LOCAL_CPP_FEATURES += rtti
LOCAL_LDLIBS := -lGLESv1_CM -llog
include $(BUILD_SHARED_LIBRARY)
Тоже должно быть понятно, в LOCAL_C_INCLUDES добавляет пути где нужно искать заголовочные файлы, в LOCAL_SRC_FILES добавляем файлы с исходным кодом,
в LOCAL_SHARED_LIBRARIES прописываем зависимости приложения.
флаги rtti, exceptions отвечают за использование RTTI и исключений.
Теоретически, после выполнения описанных шагов на подключенном девайсе или эмуляторе вы увидите установленное приложение.
Грабли
1. Где искать ресурсы???
Место размещения ресурсов зависит от конкретной реализации ОС, но в большинстве случаев они приложению будет доступна папка /sdcard/Android/data/имя_пакета/files, при использовании непосредственно пути может быть ошибка доступа или ошибка поиска файла.
Получить полный путь к директории приложения можно через функцию SDL_AndroidGetExternalStoragePath(), определенную в файле SDL_system.h
2. Использование флагов создания окна.
Комбинация SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS работает не на всех девайсах, убираем SDL_WINDOW_OPENGL или SDL_WINDOW_BORDERLESS и смотрим какой из флагов крашит программу. Не могу объяснить с чем связано, такое поведение. С флагом SDL_WINDOW_SHOWN запукается по логам один в один, как и со всеми флагами, но при этом вероятность вылета намного меньше.
3. Слишком много звуковых каналов.
Наблюдаются вылеты при вызове функции SDL_mixer::Mix_AllocateChannels(N>16) c ошибкой, что невозможно иниализировать звук. Обходится снижением запрошенного числа каналов, насколько корректно решать эту проблему таким способом я не знаю.
4. stlport vs gnustl
Вылет при использовании stlport, нарвался на этот баг при обходе вектора с использованием итераторов на эмуляторе Nexus 7 (Android 4.0.3). Опять же не могу объяснить факт сей ошибки, решилось использованием gnustl при сборке приложения.
5. Мое кунфу сильнее твоего.
Использование библиотеки с именем, похожим на имя той, что уже есть в системе приводит к загрузке чужой библиотеки, в которой возможно нет необходимых функций. Ошибка появилась из-за того, что я собираю свою версию libpng.so, решение было найдено на stackoverflow [12], исправилось заменой имени библиотеки libpng.so на libpnggo.so
В заключении...
Работает! Почти не отличается от ББ! Доволен ли я? Не очень!
Дело в том, что толи я криворукий, толи лыжи не едут, но на планшете приложение получилось крайне медленным (10-12 fps для крайне простой картинки результат унылый), думаю, вина тут в руках и незнании матчасти. SDL — отличная библиотека в обеих реинкарнациях, и много действительно хороших игр использует её, а также портрировано на андроид [13].
Потраченного времени на создание порта не жаль точно, получен определенный опыт и много положительных эмоций, когда игра взлетела. Тем, кто ещё раздумывает пробовать или нет, однозначно пробовать, не откладывайте на потом!
З.Ы. За развитием проекта всегда можно посмотреть тут [1].
Автор: dalerank
Источник [14]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/android-development/67960
Ссылки в тексте:
[1] Ремейк игры Caesar III©: https://bitbucket.org/dalerank/caesaria/wiki/Home
[2] исследования декомпилированного кода оригинальной игры: http://habrahabr.ru/post/221913/
[3] вот такой планшет: http://www.samsung.com/us/support/owners/product/SGH-I957ZKAATT
[4] libsdl-android: https://github.com/pelya/commandergenius
[5] dl.google.com/android/ndk/android-ndk-: http://dl.google.com/android/ndk/android-ndk-
[6] dl.google.com/android/adt/adt-bundle-linux-: http://dl.google.com/android/adt/adt-bundle-linux-
[7] bitbucket.org/dalerank/caesaria: https://bitbucket.org/dalerank/caesaria
[8] списка изменений: http://habrahabr.ru/post/189924/
[9] гайд потолще: https://wiki.libsdl.org/MigrationGuide
[10] статью: http://www.dinomage.com/2013/01/howto-sdl-on-android/
[11] hg.libsdl.org/SDL: http://hg.libsdl.org/SDL
[12] stackoverflow: http://stackoverflow.com/questions/20698905/unsatisfiedlinkerror-in-android-4-4-libdevil-cannot-locate-symbol-png-set-longj
[13] портрировано на андроид: https://github.com/pelya/commandergenius/tree/sdl_android/project/jni/application
[14] Источник: http://habrahabr.ru/post/233737/
Нажмите здесь для печати.