Первое приложение
Наконец, мы готовы создать наше первое приложение!Итак, создайте новый шаблонный проект cocos2d (или используйте тот, который был создан в прошлом уроке).
В этом уроке мы поиграем с распознаванием касаний.
Откройте файл HelloWorldLayer.m и в методе -(id)init после строчки [self addChild: label];
добавьте следующие строки:
label.tag = 13;
self.isTouchEnabled = YES;
Таким образом, наш метод выглядит так:
-(id) init
{
if( (self=[super init])) {
CCLabelTTF *label = [CCLabelTTF labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:64];
CGSize size = [[CCDirector sharedDirector] winSize];
label.position = ccp( size.width /2 , size.height/2 );
[self addChild: label];
label.tag = 13;
self.isTouchEnabled = YES;
}
return self;
}
Что же делают наши две строки?
Сначала мы присваиваем нашей надписи тэг - уникальный номер, по которому ее можно будет идентифицировать в нашем HelloWorldLayer.
Поскольку мы не храним label как отдельный член класса, а добавляем его в коллекцию, то, чтобы иметь возможность обращаться к нашей label, мы используем этот номер.
Почему именно 13? В данном случае - просто так. Вообще, по-хорошему, в вашем коде не должно быть случайных значений - лучше создать целочисленную константу с самоописывающим именем и присвоить ее. В дальнейшем мы так и будем делать.
Важно: тэг - это положительное число и для каждого объекта он должен быть разный (иначе непонятно, какой объект из двух объектов с одинаковыми тэгами мы получим).
Далее, присваивая YES свойству isTouchEnabled, мы сообщаем, что хотим получать события о касаниях.
Для обработки касаний используются несколько методов, один из них это ccTouchesBegan:withEvent:. Он вызывается каждый раз, когда начинаются касания.
Обработка касаний
Добавим в код нашего класса HelloWorldLayer этот метод:
-(void)ccTouchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
CCLabelTTF* label = (CCLabelTTF*)[self getChildByTag:13];
label.scale = CCRANDOM_0_1();
}
Что делает этот код?
Каждый раз, когда пользователь касается экрана, мы:
1-ая строка: получаем объект с тэгом 13 (как мы помним, это надпись) и приводим его к типу CCLabelTTF, сохраняя под идентификатором label
2-ая строка: нашему объекту label присваиваем scale (масштаб) от 0 до 1, используя встроенный в cocos2d макрос CCRANDOM_0_1(), который возвращает случайное число от 0 до 1.
Если теперь запустить наше приложение и несколько раз потыкать по экрану, то надпись будет меняться в размерах :)
Важно обратить ваше внимание на первую строчку. Мы используем явное приведение возвращаемого методом getChildByTag элемента к CCLabelTTF, поскольку знаем, что только что его туда положили.
Но хорошая практика в таких случаях - проверять, что объект действительно предполагаемого типа (иначе нас ждет крах приложения с ошибкой EXC_BAD_ACCESS).
Можно переписать код нашего метода следующим образом:
CCNode* node = [self getChildByTag:13];
NSAssert([node isKindOfClass:[CCLabelTTF class]],
@"node is not a CCLabelTTF!");
label.scale = CCRANDOM_0_1();
NSAssert([node isKindOfClass:[CCLabelTTF class]],
@"node is not a CCLabelTTF!");
CCLabelTTF* label = (CCLabelTTF*)node;
Мы вызываем NSAssert и предполагаем, что наш node имеет класс CCLabelTTF. Если это правда - все будет в порядке, если нет - приложение упадет и напишет нам указанную во втором параметре ошибку.
Вы можете спросить - а если я каждый раз буду проверять, не будет ли моя программа тормозить?
Нет! Вызовы NSAssert убираются в Release-версии приложения автоматически, поэтому код по производительности остается тем же самым.
Итоги
Итак, мы создали наше первое приложение :) Не просто создали, но и написали реальный, работающий код!
Дальше нас ждет более подробный разбор различных функций cocos2d, ну а пока хочется отметить несколько важных моментов, которые могут встретиться вам при разработке приложений:
- У каждого устройства Apple (iPod, iPhone, iPad) разных поколений есть свои, пусть и незначительные (а иногда, значительные) отличия, про которые не стоит забывать при разработке игр. Например, у iPhone 4 оперативной памяти 512 мегабайт, а у iPod Touch 4 - 256 мегабайт, как и у iPhone 3Gs и iPad 1го поколения. Поэтому, если у вас игра идет хорошо на одном устройстве, это не значит, что она будет хорошо идти на всех. Технические спецификации можно посмотреть на сайте Apple для iPhone, iPod, iPad.
- Опять же, помните, что в мире еще много старых устройств (у меня у самого iPhone 3Gs :) ), поэтому, выпуская игру, идущую лишь на самых новых устройствах, вы можете лишить себя большого количества потенциальных покупателей
- По поводу оперативной памяти - сейчас используются разное количество оперативной памяти (128 мб, 256 мб, 512 мб, а теперь, кажется, и 1 гб) - но, конечно, не вся эта память доступна приложению - большой кусок использует сама операционная система, а так же работающие в background-режиме процессы. По существующим подсчетам, на устройствах с 128 мб памяти вам доступно (до memory warning) 20-25 мб, максимум 35-40 мб (далее система просто убьет приложение). На устройствах с 256 мб памяти - 80-90 мб до предупреждения, 120-150 максимум. На устройствах с 512 мб памяти - 260-300 мб до прежупреждения, 340-370 максимум.
- О memory warning'ах (ошибка, связанных с малым количеством оставшейся памяти). Предупреждение первого уровня обычно можно игнорировать (если не планируется более выделять памяти), а вот предупреждение второго уровня - это, по сути, предупреждение от системы о том, что если приложение сейчас же не освободит память, оно будет убито. Освобождать память нужно в вашем классе AppDelegate, в методе
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application. Например, таким образом:- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application{[[CCDirector sharedDirector] purgeCachedData];[[CCTextureCache sharedTextureCache] removeUnusedTextures];}Здесь, мы просим cocos2d освободить кэшированные данные и убрать из памяти неиспользуемые текстуры. Конечно, в сложных приложениях может потребоваться более сложная схема очистки памяти. Более того, помните, что приложение может притормаживать при освобождении больших кусков памяти. А если cocos2d удалит текстуру, которую нужно использовать через несколько кадров, то придется снова загружать ее, на что также тратится драгоценное время.
- Помните о приложениях, работающих в бэкграунде - можно попробовать протестировать игру при нескольких таких приложениях и посмотреть на ее поведение.
- Замерить употребляемую память можно, используя приложение Instruments - более подробно о его использовании можно почитать в интернете :)
- Всегда тестируйте игру на устройстве (по крайней мере, каждое важное изменение в игре), а не только на симуляторе, поскольку производительность симулятора и производительность устройства - совершенно разные. Аналогично, потребление памяти (игра в симуляторе может получить гораздо больше памяти, чем на устройстве) + многих функций, таких как акселерометр, GPS, камера и т.д. на симуляторе банально нет :) К тому же, поведение на симуляторе иногда может отличаться от поведения на устройстве.
- Для измерения производительности игры используйте Release-сборку, а не Debug-сборку, поскольку в Debug-сборке, например, не отключено логирование и некоторые другие функции, что в целом может повлиять на производительность.
Уфф, советов получилось много. Какие-то из них могут быть непонятны, но, как всегда, не стоит пугаться - когда мы будем сталкиваться с этими вещами на практике, я снова буду упомянать о них и вы сможете понять, в чем дело :)
Как всегда, задавайте вопросы в комментарии - возможно, благодаря вам я смогу улучшать качество своих лекций :)
Иллюстрации и примеры кода взяты из книги Learn cocos2d Game Development with iOS 5.
Посетите также блог автора книги ("Learn Cocos2d", Steffen Itterheim)
отлично! спасибо за доступное изложение темы:)
ОтветитьУдалить