Дорогие друзья, сегодня я расскажу вам о фреймворке высокого уровня на Lua для мобильных платформ собственной разработки. Как вы уже, наверное, догадались из названия, этот фреймворк использует другой низкоуровней фреймворк для отрисовки графики и для взаимодействия с системой. В качество него выступает MOAI. Для минимального ознакомления с ним, я рекомендую прочитать мою предыдущую статью habrahabr.ru/post/176765
Прежде всего, какие задачи должен был решить новый фремворк?
Во-первых, проблемы с фрагментацией экранов. А во-вторых (та-дам), хотелось иметь какой-то, пусть и простейший, графический редактор интерфейсов. В третьих, фреймворк должен был определить архитектуру и файловую структуру приложения в целом. Хочу сказать, что кода получилось немного (менее 600 строк), поэтому, даже если фреймворк вам не подойдет, как есть, будет несложно разобраться с его работай и заточить его под свои нужды.
Warning: фреймворк заточен под landscape приложения, поэтому если вам нужен портретный режим, то скорее всего придется потратить некоторое время на доработку.
Вернемся к фрагментации экранов.
Чтобы решить проблему фрагментации, нужно, чтобы приложение учитывало:
Для того, чтобы решить все эти три задачи одним махом, Corona SDK или Gideros предлагают выбрать policy масштабирования всего приложения. Наиболее адекватный из этих режимов — так называемый letterbox. Это когда приложение равномерно масштабируется до размеров экрана, но при этом остаются черные полосы по краям в случае несовпадения пропорций.
В MOAI как такового режима нет, но есть снипетс, как реализовать это в несколько строк, манипулируя параметрами viewport.
Понятно, что такая полумера не может удовлетворить по-настоящему хорошее приложение. Экраны мобильных устройств и без того малы, чтобы еще их площадь съедалась черными полосами.
Очевидно, что не обойтись без эластичной верстки (решаем проблему размеров/пропорций).
Что касается разных разрешений экрана, то это легко решается набором разной графики или же ее масштабированием. Однако, в Android/iOS эти механизмы работают по-разному, поэтому придется реализовывать его самим.
Графический редактор был написан при помощи PyQt. Он довольно прост и умеет манипулировать только спрайтами, то бишь картинками.
MOAI поддерживает отображение текста, но ни графический редактор, ни Terevaka не могут его показывать. На практике это означает, что если пове��х кнопки нужно нанести текст, то это нужно сделать программно после загрузки спрайта кнопки (либо нанести текст прямо на спрайт кнопки, лол).
Тем не менее, графический редактор — это мощный инструмент, т. к. позволяет не только разместить элементы графически, но и отделить вид от логики программы.
Графический редактор хранит файл проекта в JSON файле и экспортирует слой во внутреннее представление Terevaka (Lua файл) по принципу один файл — один слой.
Слои бывают двух типов- elastic и scalable.
Elastic слой при отображении размещает элементы в зависимости от сторон привязки. Т.е. если вы хотите, чтобы элемент при масштабировании следовал правому верхнему углу, то нужно указывать координаты относительно этого угла.
Пример, слой в редакторе:

Iphone 3.5 Inch:

Iphone 4 inch:

Ipad:

Scalable слой — это другой тип слоя, который масштабируется пропорционально, наподобие letterbox. К примеру, главное меню имеет смысл делать именно при помощи scalable слоя, но фон, однако, лучше сделать на весь экран.
Пример, слой в редакторе:

Iphone 3.5 Inch:

Iphone 4 Inch:

Ipad:

В редакторе, пропорции scalable слоя указаны фиксировано 427x320. Это пропорции айпада, уменьшенные до размера iphone. Вы можете выбрать более удобные для себя параметры, однако нужно помнить о разрешении графики, которая будет использоваться в дизайнере и непосредственно в приложении. Для себя я использую 853х640 (изменять параметр нужно прямо в исходниках графического редактора) и заливаю в редакторе retina графику. В самом приложении, как правило, использую текстуры еще более высокого разрешения, чтобы графика соотвествовала большим ретина экранам, а во время загрузки слоя указываю параметр dpiMultiplier, чтобы спрайты загрузились нужного размера.
Причина по которой я захардкодил 427х320 попорции — с размерами/разрешениями легко запутаться, поэтому кто понимает что к чему, разберется, как адаптировать это под свой случай.
Так, комбинируя подходы, можно довольно быстро создавать гибкую графику.
Файлы со слоями хранятся в директории ./res/layout/ по аналогии с Android.
Разные разрешения экрана поддерживаются двойным набором графики.
Набор графики с обычным разрешением хранится в ./res/drawable-mdpi/, а ретина — в ./res/drawable-xhdpi/. Если разрешение экрана не совпадает с одним из этих, то будет взят наиболее подходящий набор и смасштабирован. Директории ./res/drawable-ldpi и ./res/drawable-hdpi пока не поддерживаются движком.
Важный момент — при загрузке слоя желательно использовать упакованные спрайты в одну текстуру для того, чтобы оптимизировать объем расходуемой памяти. В фрейворке поддерживается MOAI формат, в который умеет конвертировать платный TexturePacker.
Warning: не используйте в TexturePacker упаковку текстур с удалением пустых областей, т. к. в экспортере в формат MOAI есть баг и графика в итоге поплывет.
Для получения спрайта из слоя используйте функцию findPropById (опять-таки аналогия с Android)
Для обработки нажатия на спрайт, достаточно приаттачить специальный callback (см. пример в terevaka-samples).
Другие различные примеры использования смотрите в проекте terevaka-samples. Чтобы запустить пример, скопируйте tereavaka в папку примера, а еще лучше — сделайте в нее симлинк.
Чтобы протестировать приложение под разными экранами, вовсе не нужно много разных устройств — используйте профили запуска. Готовые профили лежат в каталоге ./terevaka/profiles.
Для запуска с профилем, используйте команду moai ./terevaka/profiles/ipad.lua main.lua, где ipad.lua — профиль айпада. В профиле как правило 3-4 строки, вы можете с легкостью создать свои профили.
Спрайты для ui builder нужно сохранять в разрешении mdpi.
Изначально проект начинался, как выделение некого общего кода из кода моей новой игры. В попытке структурировать, как сам код, так и требования к нему, привели к появлению фреймворка, а затем, используя мои старые наработки, и графического дизайнера к нему. Помимо этого, пришлось дорабатывать и сам MOAI, однако благодаря быстрому отклику его разработчиков, все изменения уже внесены в основной репозиторий.
Также — это показательный опыт, что не нужно боятся писать свои библиотеки, если четко понимаете требования к ним, а также если пишете на скриптовом языке :)
Terevaka: github.com/Nepherhotep/terevaka
Samples: github.com/Nepherhotep/terevaka-samples
UI Builder: github.com/Nepherhotep/terevaka-ui-builder
Official MOAI: github.com/moai/moai-dev
My fork: github.com/Nepherhotep/moai-dev
Прежде всего, какие задачи должен был решить новый фремворк?
Во-первых, проблемы с фрагментацией экранов. А во-вторых (та-дам), хотелось иметь какой-то, пусть и простейший, графический редактор интерфейсов. В третьих, фреймворк должен был определить архитектуру и файловую структуру приложения в целом. Хочу сказать, что кода получилось немного (менее 600 строк), поэтому, даже если фреймворк вам не подойдет, как есть, будет несложно разобраться с его работай и заточить его под свои нужды.
Warning: фреймворк заточен под landscape приложения, поэтому если вам нужен портретный режим, то скорее всего придется потратить некоторое время на доработку.
Вернемся к фрагментации экранов.
Чтобы решить проблему фрагментации, нужно, чтобы приложение учитывало:
- Разные размеры экранов
- Разные разрешения
- Разные пропорции
Для того, чтобы решить все эти три задачи одним махом, Corona SDK или Gideros предлагают выбрать policy масштабирования всего приложения. Наиболее адекватный из этих режимов — так называемый letterbox. Это когда приложение равномерно масштабируется до размеров экрана, но при этом остаются черные полосы по краям в случае несовпадения пропорций.
В MOAI как такового режима нет, но есть снипетс, как реализовать это в несколько строк, манипулируя параметрами viewport.
Понятно, что такая полумера не может удовлетворить по-настоящему хорошее приложение. Экраны мобильных устройств и без того малы, чтобы еще их площадь съедалась черными полосами.
Очевидно, что не обойтись без эластичной верстки (решаем проблему размеров/пропорций).
Что касается разных разрешений экрана, то это легко решается набором разной графики или же ее масштабированием. Однако, в Android/iOS эти механизмы работают по-разному, поэтому придется реализовывать его самим.
Спрайтовый графический редактор
Графический редактор был написан при помощи PyQt. Он довольно прост и умеет манипулировать только спрайтами, то бишь картинками.
MOAI поддерживает отображение текста, но ни графический редактор, ни Terevaka не могут его показывать. На практике это означает, что если пове��х кнопки нужно нанести текст, то это нужно сделать программно после загрузки спрайта кнопки (либо нанести текст прямо на спрайт кнопки, лол).
Тем не менее, графический редактор — это мощный инструмент, т. к. позволяет не только разместить элементы графически, но и отделить вид от логики программы.
Графический редактор хранит файл проекта в JSON файле и экспортирует слой во внутреннее представление Terevaka (Lua файл) по принципу один файл — один слой.
Слои бывают двух типов- elastic и scalable.
Elastic слой при отображении размещает элементы в зависимости от сторон привязки. Т.е. если вы хотите, чтобы элемент при масштабировании следовал правому верхнему углу, то нужно указывать координаты относительно этого угла.
Пример, слой в редакторе:

Iphone 3.5 Inch:

Iphone 4 inch:

Ipad:

Scalable слой — это другой тип слоя, который масштабируется пропорционально, наподобие letterbox. К примеру, главное меню имеет смысл делать именно при помощи scalable слоя, но фон, однако, лучше сделать на весь экран.
Пример, слой в редакторе:

Iphone 3.5 Inch:

Iphone 4 Inch:

Ipad:

В редакторе, пропорции scalable слоя указаны фиксировано 427x320. Это пропорции айпада, уменьшенные до размера iphone. Вы можете выбрать более удобные для себя параметры, однако нужно помнить о разрешении графики, которая будет использоваться в дизайнере и непосредственно в приложении. Для себя я использую 853х640 (изменять параметр нужно прямо в исходниках графического редактора) и заливаю в редакторе retina графику. В самом приложении, как правило, использую текстуры еще более высокого разрешения, чтобы графика соотвествовала большим ретина экранам, а во время загрузки слоя указываю параметр dpiMultiplier, чтобы спрайты загрузились нужного размера.
Причина по которой я захардкодил 427х320 попорции — с размерами/разрешениями легко запутаться, поэтому кто понимает что к чему, разберется, как адаптировать это под свой случай.
Так, комбинируя подходы, можно довольно быстро создавать гибкую графику.
Файлы со слоями хранятся в директории ./res/layout/ по аналогии с Android.
Фрагментация разрешений экранов
Разные разрешения экрана поддерживаются двойным набором графики.
Набор графики с обычным разрешением хранится в ./res/drawable-mdpi/, а ретина — в ./res/drawable-xhdpi/. Если разрешение экрана не совпадает с одним из этих, то будет взят наиболее подходящий набор и смасштабирован. Директории ./res/drawable-ldpi и ./res/drawable-hdpi пока не поддерживаются движком.
Важный момент — при загрузке слоя желательно использовать упакованные спрайты в одну текстуру для того, чтобы оптимизировать объем расходуемой памяти. В фрейворке поддерживается MOAI формат, в который умеет конвертировать платный TexturePacker.
Warning: не используйте в TexturePacker упаковку текстур с удалением пустых областей, т. к. в экспортере в формат MOAI есть баг и графика в итоге поплывет.
Разное
Для получения спрайта из слоя используйте функцию findPropById (опять-таки аналогия с Android)
Для обработки нажатия на спрайт, достаточно приаттачить специальный callback (см. пример в terevaka-samples).
Другие различные примеры использования смотрите в проекте terevaka-samples. Чтобы запустить пример, скопируйте tereavaka в папку примера, а еще лучше — сделайте в нее симлинк.
Чтобы протестировать приложение под разными экранами, вовсе не нужно много разных устройств — используйте профили запуска. Готовые профили лежат в каталоге ./terevaka/profiles.
Для запуска с профилем, используйте команду moai ./terevaka/profiles/ipad.lua main.lua, где ipad.lua — профиль айпада. В профиле как правило 3-4 строки, вы можете с легкостью создать свои профили.
Спрайты для ui builder нужно сохранять в разрешении mdpi.
Резюме
Изначально проект начинался, как выделение некого общего кода из кода моей новой игры. В попытке структурировать, как сам код, так и требования к нему, привели к появлению фреймворка, а затем, используя мои старые наработки, и графического дизайнера к нему. Помимо этого, пришлось дорабатывать и сам MOAI, однако благодаря быстрому отклику его разработчиков, все изменения уже внесены в основной репозиторий.
Также — это показательный опыт, что не нужно боятся писать свои библиотеки, если четко понимаете требования к ним, а также если пишете на скриптовом языке :)
Ссылки
Terevaka: github.com/Nepherhotep/terevaka
Samples: github.com/Nepherhotep/terevaka-samples
UI Builder: github.com/Nepherhotep/terevaka-ui-builder
Official MOAI: github.com/moai/moai-dev
My fork: github.com/Nepherhotep/moai-dev
