[Перевод] Разработка HTML5-игр в Intel XDK. Часть 2. Cocos2d-JS
Продолжаем серию материалов по Intel XDK (первая часть была тут). Сегодня поговорим о движке Cocos2d-JS и о его внутреннем устройстве.
Движок
Cocos2d-JS — это платформа для разработки игр. Как и многие JavaScript-платформы, которые используются в веб-программировании, он облегчает процесс создания приложений благодаря некоторому уровню абстракции и поддержке определённых конструкций и приёмов работы. Среди них — обработка событий ввода, отображение объектов на экране, игровой цикл. Движок создан с учётом собственной концепции устройства игры.
Игра в Cocos2d-JS
В Cocos2d-JS имеются так называемые узлы (nodes). Именно их конфигурация и взаимоотношения определяют то, какой будет игра. Они — базовые блоки приложения. Вот три типа узлов, которыми мы будем пользоваться. Это сцены (Scenes), слои (Layers) и спрайты (Sprites).
Структура узлов в проекте, построенном на Cocos2d-JS
Сцены — узлы верхнего уровня. Это значит, что они представляют собой наиболее общую абстракцию, находящуюся на верхнем уровне иерархии объектов, из которых состоит приложение. Их можно сравнить с уровнями игры или со сценами в фильме. В проекте Cocos2d-JS имеется так называемый «управляющий объект» (Director). Иногда его называют «режиссёром». Именно он исполняет сцены в заданном порядке. Сцены можно запускать на выполнение в любой последовательности, делать это допустимо сколько угодно раз. Итак, на самом высоком уровне абстракции, игра на Cocos2d-JS — это просто набор сцен, которые запускаются в определённом порядке, формируя игровой процесс. Сцены, в свою очередь, содержат слои и спрайты.
Слои — контейнеры для других узлов, которые могут накладываться друг на друга. Они — следующий уровень иерархии в игре. Это означает, что некая сцена может содержать множество слоёв, каждый из который может включать в себя другие узлы, которые нужно сгруппировать. Например, один слой может содержать объекты фона, ещё один — игрового персонажа, ещё один — табло для вывода набранных игроком очков.
Спрайты — это то, что создаёт основную массу интерактивных игровых элементов. Они, во-первых, могут подвергаться модификации, перемещению, например, а во-вторых — с ними обычно ассоциируются какие-либо изображения. Спрайтом может быть всё, что угодно — пункт меню, персонаж игры, элемент игрового мира.
Действия и иерархия
Спрайты можно перемещать, делается это исключительно после применения к ним так называемых «действий» (Actions).
Действие — это именно то, что первое приходит в голову, когда видишь это слово. Хотя, нужно уточнить, что не спрайты выполняют действия, а действия выполняются над спрайтами.
Действия — это обычно перемещения объектов по экрану. Они могут быть очень разными. Например — мгновенная смена местоположения, перемещение, занимающее определённое время, или такое, параметры которого задаёт некая функция (какая-нибудь кривая или другой способ указания пути).
Взаимоотношения узлов определяются отношениями типа «родитель-потомок». Узел может быть родителем или потомком какого-нибудь другого узла. Узлы могут иметь множество потомков, но только одного родителя.
Любые преобразования, выполняемые с узлом-родителем, будут применены и к его потомкам. Это можно сравнить с детским поводком для обучения ходьбе, который одним концом привязан к рюкзаку малыша, а другим — к руке родителя. Если, на прогулке, остановится родитель — не пойдёт дальше и ребёнок.
В плане построения иерархии узлов особых правил нет. Это значит, например, что спрайты могут быть прямыми потомками сцен, а слои могут быть прямыми потомками спрайтов.
Настройка шаблонной игры
Теперь, когда мы рассмотрели базовые концепции, пришло время применить полученные знания на практике, взглянуть на то, как всё это выглядит в коде. Для этого откройте файл app.js, созданный при разворачивании шаблона игры. Он находится в папке www/src. Внесём в него кое-какие изменения.
- Вставьте следующий участок кода в тело функции ctor, в HelloWorldLayer. Нужно это для того, чтобы добавить на слой новый спрайт — надпись.
var tsLabel = new cc.LabelTTF("Tunnel Snakes Rule!", "Arial", 38); tsLabel.x = size.width / 2; tsLabel.y = size.height / 2; this.addChild(tsLabel, 5);
- Поэкспериментируйте с числами, которые мы записываем в tsLabel.x и tsLabel.y, чтобы поменять позицию надписи Сейчас строка выровнена по центру экрана.
Самые основы движка Cocos2d-JS мы разобрали. Теперь займёмся изучением шаблонного проекта.
Подробности о шаблонном проекте
Шаблонная игра состоит из одной сцены с одним слоем, который является потомком сцены и родителем для нескольких спрайтов.
Шаблон
Спрайты — это фоновое изображение, текст «Hello World» и кнопка выключения питания. В свою очередь, сцена и слой не имеют собственных видимых компонентов.
Шаблон приводят в движение два действия. Первое управляет надписью «Hello World», второе отвечает за фоновое изображение. Их эффект вы уже, наверняка, видели, когда запускали проект в эмуляторе.
Классы
API Cocos2d-JS состоит из основного объекта «cc», в котором и расположен весь движок. Объект cc.Class в движке используется для реализации классов. Класс можно представить себе в виде чертежа или рецепта изготовления блюда. Рецепт — это лишь описание, на его основе можно приготовить что-нибудь вкусное, но сам он в пищу не годится.
Cocos2d-JS предоставляет разработчику классы для того, чтобы он мог создавать собственные объекты — узлы. Надо сказать, что готовых узлов, которые можно взять и тут же использовать, здесь нет. Если нужен узел — сначала его нужно создать своими силами.
Если, в справочнике по API Cocos2d-JS, развернуть ветвь cc.Class, а в ней — cc.Node, там можно обнаружить cc.Scene, cc.Layer и cc.Sprite. Мы можем использовать эти классы для создания собственных сцен, слоёв и спрайтов с помощью метода extend — так, как это обычно делается в JavaScript.
Код узла
В нижней части файла app.js (в папке src) можно обнаружить такой код:
var HelloWorldScene = cc.Scene.extend({
onEnter: function() {
this._super();
var layer = new HelloWorldLayer();
this.addChild(layer);
}
});
Здесь создаётся новая сцена, которая называется HelloWorldScene. Метод onEnter выполняется всякий раз, когда сцену исполняет управляющий объект (Director), или когда сцена создаётся. Так как мы переопределяем метод onEnter, необходимо вызвать это метод родительского класса командой this._super ();, в самом начале кода метода. Это позволяет отработать родительскому методу onEnter, сделать за нас всё то, что предусмотрено логикой системы для объектов класса Scene, и, таким образом, избавить от массы проблем. Это можно сравнить с приготовлением, например, пряников. Можно взять рецепт, собрать муку, масло, яйца, да мало ли что ещё. Потом завести тесто, разогреть духовку… А можно взять полуфабрикат, где уже всё необходимое есть, высыпать в хлебопечку, долить воды и нажать на кнопку. Вот в этом случае мы, вызывая метод родительского класса, просто нажимаем на кнопку. После того, как он отработает, мы просто создаём новый слой и добавляем его в качестве потомка к сцене.
Такой шаблон проектирования используется при создании практически всех узлов. Сначала создаём узел-потомок, потом добавляем его к родительскому (тому, в коде которого находимся) узлу. Определение слоя HelloWorldLayer в файле app.js выполнено, исходя из вышеописанных принципов. Там лишь содержится больше кода: инициализация слоя, создание нескольких узлов, настройка их местоположения и перемещения.
/////////////////////////////
// 3. Добавьте код ниже...
// добавляем надпись "Hello World"
// создаём и инициализируем надпись
var helloLabel = new cc.LabelTTF("Hello World", "Arial", 38);
// размещаем надпись по центру экрана
helloLabel.x = size.width / 2;
helloLabel.y = 0;
// добавляем надпись в качестве потомка данного слоя
this.addChild(helloLabel, 5);
cc.LabelTTF — это особый вид спрайта, который представляет собой текст. Этот узел можно располагать на экране и перемещать, как и любой другой.
Обратите внимание на метод «ctor». Он играет роль конструктора, который исполняется всякий раз, когда создаётся объект.
Продолжаем настраивать шаблонный код
Вернёмся к тому спрайту, который мы добавили в проект выше, попытаемся его немного изменить для того, чтобы лучше понять устройство проекта.
- Найдите следующий код в методе ctor:
helloLabel.runAction( cc.spawn( cc.moveBy(2.5, cc.p(0, size.height - 40)), cc.tintTo(2.5,255,125,0) ) );
Замените его на нижеприведённый фрагмент для того, чтобы изменить поведение текста «Hello World».helloLabel.runAction( cc.sequence( cc.spawn( cc.moveBy(2.5, cc.p(0, size.height - 40)), cc.tintTo(2.5,255,125,0) ), cc.delayTime(1.5), cc.moveBy(0.2, cc.p(0, size.height + 40)) ) );
- В том же методе найдите такой код:
tsLabel.y = size.height / 2;
И замените его на такой:tsLabel.y = 0;
- Добавьте в тот же метод такую строчку:
tsLabel.runAction(cc.moveBy(4, cc.p(0, size.height - 40)));
Если всё сделано верно, вы увидите, как надпись «Tunnel Snakes Rule!» летит вслед за «Hello World», а когда долетает до верха экрана — последняя исчезает.
Экран приложения после модификации кода
Использование управляющего объекта
Теперь, когда мы взглянули на код приложения, давайте посмотрим на то, что приводит его в движение.
Если заглянете в main.js, там окажется много непонятного, но пока не обращайте внимания ни на что, кроме небольшого фрагмента, который расположен почти в самом конце.
// загружаем ресурсы, заданные в g_resources
// определение g_resources можно найти в www/src/resource
cc.LoaderScene.preload(g_resources, function () {
// загружаем и запускаем сцену HelloWorldScene
// определение можно найти в www/src/app.js
cc.director.runScene(new HelloWorldScene());
}, this);
Метод runScene управляющего объекта вызывается для того, чтобы запустить на выполнение первую сцену в игре. Этот метод можно вызывать где угодно в коде, чтобы переключаться между сценами.
Выводы
Подведём итоги сегодняшнего занятия.
- Игра состоит из узлов (nodes)
- Сцены — это верхний уровень иерархии проекта. Они содержат узлы, их можно «воспроизводить» с помощью управляющего объекта (Director).
- Сцены содержат слои, которые могут быть расположены друг над другом.
- Слои содержат спрайты, 2D-фигуры, часто анимированные, которые формируют различные части сцены.
- Над спрайтами можно выполнять действия — благодаря этому они перемещаются.
- Узлы связаны друг с другом благодаря отношениям типа «родитель-потомок», эти отношения определяют иерархию узлов.
- Шаблонный игровой проект состоит из одной сцены, с одним слоем, на котором расположены спрайты.
- В Cocos2d-JS имеется встроенная объектно-ориентированная модель разработки, основанная на классах.
- Сцена HelloWorldScene содержит слой HelloWorldLayer.
- Слой HelloWorldLayer — это потомок сцены HelloWorldScene. Он, в свою очередь, содержит спрайты.
- Управляющий объект (Director) вызывается для запуска первой сцены в файле main.js
Теперь вы знаете о Cocos2d-JS столько, что уже почти готовы к созданию собственной игры. В следующей части мы этим и займёмся.