Cocos2d-x: Пишем на Lua
Доброго времени суток.Начнем с того, что я не нашел на хабре туториалов по Cocos2d и Lua, поэтому мне пришлось много страдать и чтобы вы не повторяли моих ошибок я решил написать пост. В этой статье я расскажу как создать простую игру используя Сocos2d-x, Cocos Code IDE и Lua. Ранее, я уже писал про создание игр на Love2d. В этой статье я адаптирую старый туториал для кокоса и как это запустить на андроиде (Ни яблока, ни мака у меня нету).
Что нам понадобится? Список важных вещей: Java JDK Сам Cocos2d-x. На момент выхода этой статьи вышел Cocos2d-x 3.2 и скачать его можно здесь. Нужно скачать той же разрядности, что и JDK IDE для lua. Разработчики движка постарались и выпустили свой IDE на основе Eclipse. Качаем здесь. [Windows-only]Python 2.7. Лежит вот тут. Если вы хотите писать игры под андроид, то придется скачать еще пару вещей, а именно: Android SDK. Если вы не собираетесь писать под андроид, то лучше найти вкладку «GET THE SDK FOR AN EXISTING IDE» Android NDK. Я использую Android NDK r9, а с r10 возможны проблемы Apache Ant. У меня стоит 1.9.4 Установка Сначала поставим Java JDK и Python. После распакуйте cocos2d-x и Cocos Code IDE (Если вы скачивали zip версию, если нет, просто запустите установку) в удобное для вас место. Распаковываем Android SDK, NDK и Apache Ant так же в удобное место. Путь к ним не должен содержать пробелов во избежание проблем. Открываем папку с SDK, находим SDK Manager. Запускаем и ставим нужные для нас версии API и всю папку Tools.Запускаем Cocos Code IDE. В Window→Preferences→Cocos указываем нудные пути. У меня это выглядит так: .Теперь кликаем по вкладке Lua которая находится во вкладке Cocos и выбираем путь к cocos2d-x: Настроено.Немного теории Cocos2d-x — кроссплатформенный движок, написанный на С++, был создан как копия Cocos2d. Cocos2d использует Object C и может использоваться только для iOS.Теперь поговорим о базовой механике движка и сравним ее с Love2D. У кокоса все объекты находятся в слоях, а слои находятся в сценах. В Love2D ни слоев, ни сцен нету. Плюсы сцен и слоев в том, что с их помощью можно создавать гибкое приложение более простыми способами. Минусы в том, что для просто игры это может быть слишком громоздко и неудобно. В кокосе все представленно объектами и чтобы что-то появилось на экране надо просто добавить это на сцену, а в love2d все представленно простыми переменными и чтобы что-то появилось на экране нужно это каждый кадр рисовать. Это можно описывать достаточно долго поэтому я скажу вывод сейчас, а разницу вы сможете почувствовать сами. Cocos2d-x — большой движок с большим количеством возможностей, однако доступ к ним часто сделан не так как хотелось бы. Love2d — простой, не требующий много знаний, движок с отзывчивым коммьюнити, но с отсутствием многих нужных вещей, которые впоследствии пишут сами пользователи, но делают это вполне удачно.А теперь сам код Создадим новый проект. И у нас будет два файла в исходниках: hello2.lua и main.lua. Если вы не хотите посмотреть на чудо китайского гейм дева, то первый можно сразу удалять, а второй очистить. Он создан лоя демонстрации возможностей require. Открываем main.lua и видим кучу кода которая нужна чтобы понять как использовать порт под lua. Чтобы увидеть, что это такое нажимаем F11. Можно поиграться. Вот это бегающие существо это собака, а не белка как вы могли подумать. Посмотрели, поигрались и хватит. Удалите hello2.lua и весь код в main.lua и очизаем папку res. В папку res добавляем картинку и называем ее habr.png. Теперь пишем в main следующий код: --Все классы кокоса require «Cocos2d» --Все константы кокоса require «Cocos2dConstants»
-- Функция вывода сообщений cclog = function (…) print (string.format (…)) end
-- Эта функция выводит ошибки function __G__TRACKBACK__(msg) cclog (»\n----------------------------------------») cclog («LUA ERROR:» … tostring (msg)) cclog (debug.traceback ()) cclog (»----------------------------------------») return msg end
collectgarbage («collect») — Предотвращает утечку памяти collectgarbage («setpause», 100) collectgarbage («setstepmul», 5000)
--Теперь можно использовать файлы которые лежат в папках «src» и «res» cc.FileUtils: getInstance (): addSearchResolutionsOrder («src»); cc.FileUtils: getInstance (): addSearchResolutionsOrder («res»);
--Записываем в константы гирину и высоту экрана SCREEN_WIDTH = cc.Director: getInstance (): getWinSize ().width SCREEN_HEIGHT = cc.Director: getInstance (): getWinSize ().height
local function main () print («Resolution:» … SCREEN_WIDTH … «x» … SCREEN_HEIGHT) --Запускаем главную сцену require «mainScene.lua» end
--Вызываем функцию main local status, msg = xpcall (main, __G__TRACKBACK__) if not status then error (msg) end В функции main мы вызываем файл mainScene.lua. В нем находится главная сцена игры. Создадим его и напишем туда следующий код:
— Константы local NONE = 0 local ROTATION = 1 local SCALLING = 2 local MOVING = 3 — Переменные local state, rotation, scale, ox, oy, delta, habrImage, moving
-- Эта функция будет вызываться когда палец касается экрана local function onTouchBegan (touch, event) — Включаем следующие состояние state = (state + 1) % 4 — И возвращаем переменные к дефолту resetVariables () end
-- Эта функция вызывается постоянно, а в dt хранится время с — прошлого вызова. Если dt == 1.0, то с прошлого вызова прошла — одна секунда local function update (dt) if state == ROTATION then --крутим картинку rotation = rotation + delta * dt elseif state == SCALLING then --увеличиваем scale = scale + dt * delta elseif state == MOVING then --Здесь немного посложнее, но все же просто: --Каждый раз мы увеличивыем переменную moving, а --потом берем ее за угол для косинису и синуса --и крутим картинку по кругу moving = moving + delta * dt local radius = 50 ox = radius * math.sin (moving) oy = radius * math.cos (moving) end — В love2d мы использовали эти параметры при рисовании — Здесь у нас спрайт и нам нужно постоянно менять ему — все вручную — Меняем размер habrImage: setScale (scale) — Меняем угол habrImage: setRotation (rotation) — Меняем позицию habrImage: setPosition (cc.p (SCREEN_WIDTH / 2 + ox, SCREEN_HEIGHT / 2 + oy)) end
local function init () print («Creating main scene») — Создаем сцену local mainScene = cc.Scene: create () — Создаем слой с фоновым цветом — Здесь я бы хотел поставить паузу и рассказать более подробно — потому что у меня ушло 2 часа чтобы узнать как мне изменить цвет — фона. 1) В C++ нету функции cc.c4b (r, g, b, a) поэтому мне пришлось — догадаться, что нужно смотреть не на C++ таких случаях, а на — cocos2d-x-js, т.к. он более популярен чем cocos2d-x-lua — и если вы не можете найти нужную функцию в C++, то ищите ее в — JavaScript версии, однако это не поможет с евентами local gameLayer = cc.LayerColor: create (cc.c4b (255, 255, 255, 255)) — Создаем спрайт habrImage = cc.Sprite: create («res/habr.png») --Ставим его смещение по центру habrImage: setAnchorPoint (0.5, 0.5) --Ставим позицию на центр экрана habrImage: setPosition (cc.p (SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2)) --Добавляем его к слою gameLayer: addChild (habrImage)
state = 0 resetVariables () — Чтобы функция update вызывалась нужно сообщить кокосу, что ее нужно — вызывать cc.Director: getInstance (): getScheduler (): scheduleScriptFunc (update, 0, false) — Создаем лисениры для событий. Хочу обратить внимание, что для каждого — типа событий есть свой лисенер. local listener = cc.EventListenerTouchOneByOne: create () — Говорим лисениру, что такой то тип событий связвн с такой то функцией listener: registerScriptHandler (onTouchBegan, cc.Handler.EVENT_TOUCH_BEGAN) — Добавляем лисенер к слою local eventDispatcher = gameLayer: getEventDispatcher () eventDispatcher: addEventListenerWithSceneGraphPriority (listener, gameLayer) --Добавляем слой к сцене mainScene: addChild (gameLayer) --Запускаем или если уже что-либо запущено заменяем сцену if cc.Director: getInstance (): getRunningScene () then cc.Director: getInstance (): replaceScene (mainScene) else cc.Director: getInstance (): runWithScene (mainScene) end end
function resetVariables () rotation = 0 scale = 1 ox = 0 oy = 0 delta = 20 moving = 0 end
--Запускаем сцену init () Теперь немного о помощи с поиском ответов. Во-первых: Порт на луа практически идентичен С++ и основные отличия можно прочесть здесь. Во-вторых: как я ранее писал, если вы не можете найти что-либо в порте С++, то попробуйте поискать эту проблему для JS движка. Он более популярен чем луа, однако в нем есть множество отличий, но очень часто он мне помогал. Чтобы запустить то, что у нас вышло нажмите F11. Чтобы запустить на андроид нажмите на кнопку «Debug configurations» и выберите андроид. Для запуска нужен настроенный adb, но про это и так много статей, поэтому я не буду писать здесь об этом. На этом все Спасибо за прочтение (:
Вот что вышло в итоге: