вторник, 8 января 2013 г.

Основы. Статья 3. Класс режиссера и работа со сценами

Основы cocos2d. Статья 3. Класс режиссера и работа со сценами

Итак, в прошлых статья мы говорили о CCNode - базовом для всех объектов в cocos2d, который олицетворяет "узел", являющийся контейнером для других узлов; обсудили CCScene - "узел", представляющий в иерархии сцену на экране; узнали о CCLayer - "слой", который содержит в себе другие узлы (как мы помним, слои объединяют узлы, а сцена объединяет слои).

Теперь настало время поговорить о другом мощном классе cocos2d - классе-"режиссере" :)
Да-да, он так и называется в переводе с английского - CCDirector!

Класс CCDirector


Класс-режиссер позволяет вам управлять сценами и переходами между ними.
По сути, это - сердце движка cocos2d.
С точки зрения программирования, этот класс реализует паттерн "Одиночка" (Синглтон). Если вы не знаете, что такое синглтон - я напишу об этом чуть позже в этом посте - а пока достаточно знать, что синглтон - это объект класса, который может быть создан только в единственном экземпляре (и доступен этот объект глобально из всего приложения).

Возможно, вы помните в одном из наших первых туториалов, когда мы обсуждали строение шаблона приложения, в файле AppDelegate.m был вызов к [CCDirector sharedDirector] - этот кусок кода как раз возвращает нам объект класса-режиссера.

Режиссер хранит в себе глобальные настройки cocos2d и управляет сценами.
Вот его функции:

  • Предоставление доступа к текущей сцене
  • Запуск, замена, добавление и удаление сцен
  • Доступ к глобальной конфигурации cocos2d
  • Доступ к OpenGL
  • Пауза, продолжение и остановка игры
  • Конвертация координат между UIKit-координатами (пиксельные координаты экрана) и координатами OpenGL (координаты от 0 до 1)
  • Определение обновления статуса игры

Работа со сценами

Как мы уже говорили, сцена (CCScene) всегда является верхним родительским элементом в иерархии узлов.
Режиссер, для отображения узлов на экране, всегда требует, чтобы ему передавался объект CCScene с иерархией узлов в нем. Кстати, ему можно также передавать класс CCSceneTransition, чтобы показывать анимацию перехода от одной сцены к другой.

Вспомним иерархию сцены: на самом верху находится сцена, ее "дочерние" элементы - слои, а каждый слой в свою очередь содержит игровые объекты.
Поскольку непосредственно в класс сцены редко добавляется какой-либо код, то часто разработчики, использующие cocos2d, создают сцену в статическом методе +(id)scene в классе-слое(то есть унаследованном от CCLayer).
Например, так:
+(id) scene {
CCScene *scene = [CCScene node];
CCLayer* layer = [HelloWorld node]; 
[scene addChild:layer];
return scene; 


Мы помним код выше из одного из наших первых туториалов.
В первой строке мы создаем сцену, во второй - создаем наш текущий слой, а затем добавляем слой в сцену и возвращаем эту сцену.
Видите, как все просто?

Теперь, чтобы запустить эту сцену с помощью режиссера, достаточно выполнить простой код:
[[CCDirector sharedDirector] runWithScene:[HelloWorldLayer scene]];

То есть, мы используем статический метод scene нашего слоя создать сцену, добавить себя в эту сцену и вернуть ее нам - а дальше полученную сцену мы отдаем в класс-режиссер с просьбой запустить ее.
Для того, чтобы запустить последующую сцену, нужно вызвать метод replaceScene:
[[CCDirector sharedDirector] replaceScene:[AnotherLayer scene]];

Хочу обратить внимание на то, что в данном случае для каждого слоя нам необходимо реализовывать метод scene вручную.

А вот как делать переход от сцены к сцене с анимацией:

CCScene* scene = [HelloWorld scene];
CCSceneTransition* tran = [CCTransitionShrinkGrow transitionWithDuration:2 scene:scene]; 

[[CCDirector sharedDirector] replaceScene:tran]; 

В первой строке мы создаем сцену, во второй создаем объект CCSceneTransition (анимация перехода), настраиваем длительность и передаем сцену, а в третьеъ строке просим нашего режиссера отобразить этот переход.

Сцены и память

Хочется обратить особое внимание вот на что.
Когда вы переходите от одной сцене к другой (вызвав replaceScene), память, выделенная для старой сцены, не освободится, пока не закончится переход на новую сцену, что создает некоторый пик потребления памяти и именно в этот момент вам могут начать приходить предупреждения от операционной системы о недостатке памяти.

Надо заметить также, что cocos2d в остальном очень хорошо заботится об очистке памяти - он убирает все запланирванные вызовы, узлы и т.д., поэтому нет необходимости заниматься чисткой вручную.

Бывает полезным использовать в вашем слое, создающем сцену, следующий код:
-(id) init {
if ((self = [super init])) {
CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self); 
}
}

-(void) dealloc {
CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);
[super dealloc]; } 

Этот код использует метод CCLOG для вывода сообщений в консоль и используется только в Debug-сборках приложения.

Он позволяет вам видеть, когда создается и уничтожается слой. Если вы увидите, что слой создан, но при этом не уничтожен - это явный знак того, что у вас теперь утечка в памяти целой сцены. Практически всегда это - ошибка разработчика, а не баг cocos2d, поэтому стоит прошерстить свой код на использование лишних retain или присваиваний этого слоя в чей-нибудь property.
Важно при работе с узлами доверить все управление памятью cocos2d и стараться не retain'ить узлы, дабы случайно не забыть их release'нуть - в крайнем случае, храните слабые ссылки на объекты, но не retain'ьте их - и тогда проблем с памятью возникнуть не должно.


В этой статье мы узнали много нового о сценах, а в следующей будет более подробно рассказано о работе с несколькими сценами и переходах между ними.


Иллюстрации и примеры кода взяты из книги Learn cocos2d Game Development with iOS 5.
Посетите также блог автора книги ("Learn Cocos2d", Steffen Itterheim)


Комментариев нет:

Отправить комментарий