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, но про это и так много статей, поэтому я не буду писать здесь об этом. На этом все Спасибо за прочтение (:

Вот что вышло в итоге:

ссылка на оригинал статьи http://habrahabr.ru/post/232013/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *