- PVSM.RU - https://www.pvsm.ru -

Сегодня я хочу рассказать об одном малоизвестном игровом движке, который мы используем уже год для кроссплатформенной разработки мобильных игр. Для 2д он нас полностью устраивает, а единственным конкурентом может быть только Unity3d из-за своего редактора. Отсутствие должного внимания к MOAI SDK [1], очевидно, связано с высоким порогом входа — сами разработчики (Zipline Games) позиционируют свой продукт как «The mobile platform for pro game developers», хотя разобравшись с установкой и настройкой окружения можно очень быстро и просто клепать игры на Lua.
Чем же мне так понравился MOAI:
Минусы и недоработки:
Опишу установку только на OS X, т.к. не имею под рукой windows системы.
Клонируем официальный репозиторий:
git clone https://github.com/moai/moai-dev.git
Запускаем скрипт, который соберет хост под нашу систему:
cd moai-dev
bin/build-osx-sdl.sh
Надеюсь все пройдет без ошибок, тогда исполняемый файл станет доступен в release/osx/host-sdl/bin/moai, сделаем на него линк (~/bin у меня добавлен в PATH):
ln -s /Users/vavius/moai-dev/release/osx/host-sdl/bin/moai ~/bin/moai
Запускаем пример, убеждаемся что все работает:
cd samples/hello-moai
moai
Видим крутящуюся фиговину и приветствующий текст:

Начнем с минимального примера — нарисуем квадратный спрайт по центру экрана:

Код:
-- 1
MOAISim.openWindow ( "sample", 600, 240 )
local viewport = MOAIViewport.new ()
viewport:setSize ( 600, 240 )
viewport:setScale ( 600, 240 )
-- 2
local layer = MOAILayer.new ()
layer:setViewport ( viewport )
-- 3
local renderTable = { layer }
MOAIGfxDevice.getFrameBuffer ():setRenderTable ( renderTable )
-- 4
local deck = MOAIGfxQuad2D.new ()
deck:setTexture ( "moai.png" )
deck:setRect ( -64, -64, 64, 64 )
-- 5
local prop = MOAIProp.new ()
prop:setDeck ( deck )
layer:insertProp ( prop )
Описание происходящего по пунктам:
Сразу бросается в глаза, что уж больно много строк нужно для казалось бы простой задачи нарисовать спрайт. Чаще всего это делается в одну строчку, а тут надо как минимум шесть. Поэтому, API предоставляемый движком не используется «как есть», а многие пишут свои обертки на Lua. В С++ части MOAI SDK отсутствуют многие привычные вещи такие как: кэш текстур, загрузка спрайтов из атласов, менеджер сцен и переходов между ними, всякие кнопки и другие гуи элементы. Все это предлагается реализовать на Lua. На общей производительности это врядли сильно скажется, поскольку большинство операций выполняются только при ининциализации сцены. Конечно, надо подходить с умом к написанию кода, не плодить лишних таблиц, использовать старые объекты, кэшировать что можно.
Допустим, не хотим квадратный квад, а хотим трапецию, вместо setRect используем setQuad:
local deck = MOAIGfxQuad2D.new ()
deck:setTexture ( "moai.png" )
deck:setQuad (
-64, 64,
64, 64,
100, -64,
-100, -64 ) -- координаты вершин с левого верхнего угла по часовой стрелке
Вот что выйдет:

Замостим фон целиком нашей картинкой. Можно использовать GL_REPEAT на текстуре, но он работает только для размеров кратных степеням двойки, и картинку с атласа не получится использовать. Поэтому воспользуемся классом MOAIGrid:
local deck = MOAIGfxQuad2D.new ()
deck:setTexture ( "moai.png" )
deck:setRect ( -0.5, -0.5, 0.5, 0.5 )
local grid = MOAIGrid.new ()
grid:initRectGrid ( 1, 1, 128, 128 )
grid:fill ( 1 )
grid:setRepeat ( true, true )
local prop = MOAIProp.new ()
prop:setDeck ( deck )
prop:setGrid ( grid )
layer:insertProp ( prop )
MOAIGrid нужен для работы с тайлами, здесь мы инициализируем карту из одного тайла размером 128x128. Затем ставим ему индекс 1 методом fill. Некоторые типы дек поддерживают индексацию, например MOAIGfxQuadDeck2D позволяет задавать много пар вершинных и UV координат для одной текстуры, что используется для представления спрайтового атласа. В данном случае в нашей деке есть только один единственный индекс 1. Включаем повторение и указываем пропу, что следует использовать сетку для рендеринга.

На этом этапе очень просто сделать анимированный прокручивающийся фон. Добавляем одну строчку в конец:
prop:moveLoc ( -128, 0, 0, 4, MOAIEaseType.LINEAR ):setMode ( MOAITimer.LOOP )
Просто в цикле двигаем наш проп на ширину одного тайла, а движок сам подставляет недостающие куски чтобы замостить весь экран:

Перемещение и вращение объектов, а также установка режимов проигрывания анимаций:
local move = prop:moveLoc ( 200, 0, 0, 2 ) -- двигаем
local rot = prop:moveRot ( 0, 0, 360, 2, MOAIEaseType.LINEAR ) -- крутим вокруг оси Z
move:setMode ( MOAITimer.PING_PONG ) -- вперед-назад
rot:setMode ( MOAITimer.LOOP ) -- цикл
По умолчанию анимации добавляются к корню action tree. Но можно их группировать:
local action = MOAIAction.new ()
action:addChild ( move )
action:addChild ( rot )
action:start ()
action:throttle ( 0.5 )
Теперь мы можем останавливать и запускать сразу обе анимации, а с помощью throttle задавать скорость воспроизведения.
Последовательность действий реализуется через Lua корутины. MOAI предоставляет класс MOAICoroutine, унаследованный от MOAIAction, что позволяет добавлять корутины в action tree. Функция blockOnAction вызывает yield пока экшн не закончится.
Двигаем картинку вправо-влево, а при достижении крайних точек делаем один полный оборот:
local function func ()
local distance = 200
while true do
local action1 = prop:moveLoc ( distance, 0, 0, 2 )
MOAICoroutine.blockOnAction ( action1 )
local action2 = prop:moveRot ( 0, 0, 360, 2 )
MOAICoroutine.blockOnAction ( action2 )
distance = -distance
end
end
local thread = MOAICoroutine.new ()
thread:run ( func )

В статье рассмотрены совсем примитивные примеры — моей целью было показать некоторые аспекты Lua API, а именно его низкоуровневость и модульность. MOAI SDK старается не принимать за нас никаких решений, не заставляет все делать каким-то одним общепризнанным способом, а оставляет полную свободу. Конечно же сообщество уже реализовало несколько высокоуровневых оберток на чистом Lua, с кэшированием текстур, гуи элементами, менеджером сцен и т.д.
Я бы не советовал использовать MOAI SDK в продакшене без знания С++, нюансов сборки под выбранную платформу и готовности что-то менять внутри. Практически каждый, кто использует MOAI SDK имеет свой форк, который немного отличается от главной ветки. Исторически это связано с тем, что у Zipline Games не было времени мержить пулл-реквесты. Однако, сейчас некоторые члены сообщества получили доступ к официальному репозиторию и разработка пошла бодрее.
Благодаря открытости мы смогли реализовать live reload кода и ресурсов прямо на девайс. Сейчас я потихоньку пилю редактор, по образу и подобию Unity3d. Хотя дела пошли медленнее после заработавшего live reload'a — его хватает с головой для невероятного ускорения разработки. Интерфейсы собираем в векторном редакторе и экпортим сразу в код (декларативного вида, вот пример: gist.github.com/Vavius/9868572 [2]). Конечно, все это можно было приделать к любому движку, к cocos2d-x вообще без проблем, к Короне посложней, но тоже реально. Вобщем, для 2д игр пересели мы с кокоса на MOAI и нисколько не жалеем, здесь как-то все более по-взрослому, гибче и круче + код чистый и красивый.
getmoai.com/ [1] — официальный сайт
getmoai.com/docs/annotated.html [3] — доки
moaiwebsite.github.io/ [4] — неофициальный сайт, пилится сообществом. Когда-нибудь станет новым лицом
github.com/makotok/Hanappe [5] — высокоуровневый Lua-фреймворк в ООП-стиле. Из всех подобных решений только этот сейчас развивается и поддерживается.
Update:
moaifiddle.com/Q09BJWGMW6/3 [6] — js версия движка. Теперь можно поиграться с движком без установки!
Автор: Vavius
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/ios/58111
Ссылки в тексте:
[1] MOAI SDK: http://getmoai.com/
[2] gist.github.com/Vavius/9868572: https://gist.github.com/Vavius/9868572
[3] getmoai.com/docs/annotated.html: http://getmoai.com/docs/annotated.html
[4] moaiwebsite.github.io/: http://moaiwebsite.github.io/
[5] github.com/makotok/Hanappe: https://github.com/makotok/Hanappe
[6] moaifiddle.com/Q09BJWGMW6/3: http://moaifiddle.com/Q09BJWGMW6/3
[7] Источник: http://habrahabr.ru/post/217653/
Нажмите здесь для печати.