Cocos2d IOS: пишем scrolling для game-магазина

в 13:00, , рубрики: Без рубрики

Добрый день.
Те, кто начал программировать на cocos2d, наверняка столкнулись с недостатком различных control-элементов. У меня была задача сделать скроллинг для игрового магазина без интеграции с UIKit стандартными средствами кокоса. Поискав в интернете, я нашла несколько реализаций для этого дела, но не устраивали некоторые вещи, например, отсутствие обработки свайп (быстрого касания) и кривое возвращение скроллинга на свою позицию. В результате, приложив определенные усилия, получила, в конечном итоге, скроллинг такого вида:

Здесь можно скачать проект.
При запуске вы увидите вот такой экран:

image image

Нажмите кнопку “Shop” — вот пример скролинга, код которого мы подробно разберем ниже.

Для начала посмотрим на файлы проекта. Серым отмечены стандартные кокосовские файлы, которые образуются при создании нового проекта. Они остаются с небольшими изменениями: в HelloWorldLayer.m переписана функция init: удалено все, что относилось к Game Center, и добавлена надпись “Shop” для входа в магазин, и соответствующая ей функция:

- (void) goToShop
{
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"ShopArt.plist"];
[[CCDirector sharedDirector] pushScene:[CCTransitionCrossFade transitionWithDuration:0.2 scene:[ShopMenu node]]];
}

В проект включены все необходимые картинки и шрифты. Картинки для магазина объединены в атлас с помощью TexturePacker. Для создания шрифтов использовался GlyphDesigner.

Также в проекте находятся вспомогательные файлы Utils.h и Utils.m. Здесь я размещаю функции преобразования размеров между устройствами и макросы определения версии IOS. Это удобно, т.к. обычно эти функции приходится вызывать из разных классов. Кроме того, в Utils есть еще одна весьма полезная функция:

CCSprite* spriteWithColor (ccColor4B bgColor, CGSize textureSize)

Эта функция создает спрайт заданного размера, цвета и прозрачности. Я часто использую эти спрайты для затемнения общего фона (например, при окончании прохождения уровня). Вместо этого, можно было бы использовать обычный однотонный *.png. Поскольку это вспомогательная функция, которая не имеет прямого отношения к scrolling для game-магазина, я не буду останавливаться на ней подробно. Прообраз этой функции взят из этого урока. Если интересно, пишите в комментариях, могу набросать несколько интересных примеров из этой серии.

Ключевыми файлами скроллинга являются 4 файла ShopMenu.h, ShopMenu.m, ShopMenuItemLabel.h, ShopMenuItemLabel.m.
В файле ShopMenu.h представлены два класса: класс сцены (ShopMenu) и содержащийся в нем класс скролинга(MenuScroll). Класс сцены стандартно отнаследован от CCScene и организован следующим образом:

Cocos2d IOS: пишем scrolling для game магазинаCocos2d IOS: пишем scrolling для game магазина

На задний план мы кладем картинку фона (CCSprite, zOrder =-2), на нее кладем затемнение, чтобы снизить яркость (CCSprite, zOrder =-1), далее идет непосредственно класс скролинга со всем содержимым (MenuScroll, zOrder =1), и самый верхний уровень — это панели с кнопкой выхода (CCSprite, zOrder =2). Класс сцены состоит из стандартных методов, в коде они снабжены подробными комментариями.

Итак, наконец мы можем обратиться к классу скролинга (MenuScroll). Рассмотрим метод initWithTop (ShopMenu.m). Основные моменты указаны цифрами в коде:

  • (1) Нужно указать количество позиций в магазине;
  • (2) Рассчитаем высоту одной строки. Например, на iphone у меня 3 строки на одном экране, таким образом высота строки = (480 – 2*57(панели))/3 = 122. В коде у меня 123 с поправкой на размер разделителей. Для IPad и IPhone5 высота будет отличатся, если вы хотите получить целое количество строк на экране;
  • (3) Считаем высоту скролинга как произведение количества строк на высоту строки. На последней картинке видно, что сам скролинг длинее экрана;
  • (4) Можно задействовать BatchNode. Обычно такие команды идут в паре:
    [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"ShopArt.plist"];
    spriteBatch = [CCSpriteBatchNode batchNodeWithFile:@"ShopArt.pvr.ccz"];
    но в нашем случае мы открыли *.plist, еще до входа в магазин, т.к. понадобилось создать спраты для верхней и нижней панели;
  • (5) Устанавливаем набор параметров. Кнопку ”Купить” необходимо блокировать при перемещении скролинга, за это отвечает параметр isDragging. Как только начинается движения пальца по экрану, параметру присваевается значение YES;
  • (6) Определяем позицию скролинга. Это точка (0,-h), где h — это высота, на которую скролинг уходит вниз за пределы видимой области (последняя картинка).
  • (7) Кнопки ”Купить” являются item’ами меню (8). Позиция кнопок не задается отдельно, а задается только для всего меню. Внутри меню мы упорядочиваем кнопки с помощью функции alignItemsVerticallyWithPadding (9). Соотвественно, нам нужно задать kPadding и высоту кнопки “Купить”. Все вместе это должно быть равно высоте строки, посчитанной в пункте (2), вне зависимости от размера шрифта. Присваивание размера кнопки осуществляется функцией [item setContentSize..] (10). Это очень удобно, т.к. мы можем задать размер кнопки, отличный от реального размера ее шрифта или спрайта;
  • (12) Когда я нажимаю кнопку “Купить”, мне бы хотелось знать код покупки, цену и т.п. Кроме того, мне бы хотелось disabl’ить кнопку покупок после совершения операции. Поэтому вместо стандартного класса CCMenuItemLabel, я создам на его основе ShopMenuItemLabel (смотрите ShopMenuItemLabel.h). В этом классе добавлены переменные num, price, maxQuantity и переписан метод setIsEnabled, который делает неактивную кнопку “Купить” полупрозрачной.
  • (13) Теперь хотелось бы наполнить наши “полки”, картинками (12), описаниями (13) и ценами (14).

Прокрутка скролинга осуществляется следующим образом: при плавном движении он следует за пальцем, при быстром движении (свайп) продолжает прокручиваться после остановки пальца. Для этого в процедуре

  • в ccTouchesBegan запомнили координату Y и время начала движения для проверки быстрых жестов;
  • в ccTouchesMoved скролинг строго двигается за пальцем;
  • в ccTouchesEnded (1) — проверяем было ли быстрое движение, в соответствии с этим перемещаем скролинг дополнительно, (2) — если скроллинг вышел за пределы допустимой области ставим его на место, (3) – проверяем, была ли нажата кнопка меню;

Вот собственно и все. Надеюсь статья будет кому-то полезной.

Автор: IrixV

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js