От переводчика
Доброго времени суток! Эта статья представляет собой перевод документации к движку Cocos2d-x.
В предыдущих частях мы уже рассмотрели большинство основных компонентов движка:
Sprite
Action
UI Components
Scene и другие
Нам осталось совсем немного для создания полноценной игры. А именно, обеспечить сам игровой процесс. Для этого, в Cocos2d-x существует диспетчер событий.
Диспетчер событий
Что такое механизм EventDispatch? EventDispatch — это механизм реагирования на пользовательские события.
Основы:
- Слушатели событий инкапсулируют ваш код обработки событий.
- Диспетчер событий уведомляет слушателей о пользовательских событиях.
- Объекты событий содержат информацию о событии.
5 типов слушателей событий
EventListenerTouch — реагирует на касание сенсорного экрана
EventListenerKeyboard — реагирует на нажатия клавиатуры
EventListenerAcceleration — реагирует на события акселерометра
EventListenMouse — реагирует на события мышки
EventListenerCustom — реагирует на настраиваемые события
FixedPriority vs SceneGraphPriority
EventDispatcher использует приоритеты, чтобы решать, какие слушатели получат событие первыми.
Fixed Priority(фиксированный приоритет) представляет целочисленное значение. Слушатели событий с более низким значение приоритета получают события на обработку, раньше, чем слушатели с высоким значением приоритета.
Scene Graph Priority — это указатель на Node-объект. Слушатели событий, чьи узлы имеют более высокое значение z-прядка(которые рисуются сверху), получают события прежде, чем слушатели, чьи узлы имеют более низкие значения z-порядка(которые рисуются снизу). Это гарантирует, что события касания получат передние элементы, как и следовало ожидать.
Помните граф сцены? Когда мы говорили об этой диаграмме?

При использовании Scene Graph Priority вы фактически проходите это дерево в обратную сторону… I, H, G, F, E, D, C, B, A. Если сработает событие, H заметит это и либо поглотит его (подробнее об этом ниже), либо пропустит дальше к I. Тоже самое с I, он либо потребит действие, либо пропустит его дальше к G, и так далее.
События касания
События касания — самые важные события в мобильном гейминге. Они легки в создании и предоставляют гибкую функциональность. Давайте уточним, что такое событие касания. Когда вы дотрагиваетесь до экрана вашего мобильного девайса, он воспринимает касание, смотрит где вы прикоснулись и решает, на что вы нажали. Затем, вы получаете ответ. Возможно, вы коснулись не активного объекта, а чего-то под ним. Событиям касания, обычно, присваивается приоритет, а отвечает событие с наивысшим приоритетом.
Как создать базовый слушатель события касания:
// Создание "одиночного" слушателя событий касания // (обрабатывается одн�� касание за раз) auto listener1 = EventListenerTouchOneByOne::create(); // срабатывает при нажатии listener1->onTouchBegan = [](Touch* touch, Event* event){ // ваш код return true; // Если вы его приняли }; // срабатывает при перемещении касания listener1->onTouchMoved = [](Touch* touch, Event* event){ // ваш код }; // срабатывает при отпускании listener1->onTouchEnded = [=](Touch* touch, Event* event){ // ваш код }; // Добавляем слушатель _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, this);
Как вы могли заметить, существуют 3 отдельных действия, которые вы можете использовать для слушателя касаний. Каждое из них вызывается при определенных условиях.
onTouchBegan — срабатывает при нажатии.
onTouchMoved — срабатывает при перемещении касания.
onTouchEnded — срабатывает при отпускании.
Поглощение событий
Когда у вас есть слушатель и вы хотите чтобы объект принял поданное событие, вы должны поглотить его. Другими словами, вы принимаете его, чтобы оно не прошло дальше, к другим объектам с более низким приоритетом. Это легко реализовать.
// Чтобы "поглотить" действие, возвращаем true // Метод onTouchBegan поглотит действие касания, // не позволяя другим слушателям использовать его listener1->setSwallowTouches(true); // Также вы должны вернуть true в onTouchBegan() listener1->onTouchBegan = [](Touch* touch, Event* event){ // ваш код return true; };
Создание событий клавиатуры
Для компьютерных игр, вам может понадобится использование клавиатуры. Cocos2d-x поддерживает клавиатуру. Как и события касания, клавиатурные события легко создаются.
// создание слушателя клавиатурных событий auto listener = EventListenerKeyboard::create(); listener->onKeyPressed = CC_CALLBACK_2(KeyboardTest::onKeyPressed, this); listener->onKeyReleased = CC_CALLBACK_2(KeyboardTest::onKeyReleased, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); // реализация прототипа callback функции void KeyboardTest::onKeyPressed(EventKeyboard::KeyCode keyCode, Event* event) { log("Key with keycode %d pressed", keyCode); } void KeyboardTest::onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event) { log("Key with keycode %d released", keyCode); }
Создание событий акселерометра
Некоторые мобильные устройства оснащены акселерометром. Акселерометр — это датчик, который измеряет перегрузку, а также изменения направления. Используется, например, когда необходимо перемещать телефон из стороны в сторону, для имитации балансирующего действия. Cocos2d-x также поддерживает эти события. Перед использованием событий акселерометра, вам необходимо подключить их.
Device::setAccelerometerEnabled(true);
// создание слушателя auto listener = EventListenerAcceleration::create(CC_CALLBACK_2( AccelerometerTest::onAcceleration, this)); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); // реализация прототипа callback функции void AccelerometerTest::onAcceleration(Acceleration* acc, Event* event) { // Processing logic here }
Создание событий мыши
Как всегда, Cococ2d-x поддерживает события мыши.
_mouseListener = EventListenerMouse::create(); _mouseListener->onMouseMove = CC_CALLBACK_1(MouseTest::onMouseMove, this); _mouseListener->onMouseUp = CC_CALLBACK_1(MouseTest::onMouseUp, this); _mouseListener->onMouseDown = CC_CALLBACK_1(MouseTest::onMouseDown, this); _mouseListener->onMouseScroll = CC_CALLBACK_1(MouseTest::onMouseScroll, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(_mouseListener, this); void MouseTest::onMouseDown(Event *event) { // для демонстрации события... EventMouse* e = (EventMouse*)event; string str = "Mouse Down detected, Key: "; str += tostr(e->getMouseButton()); } void MouseTest::onMouseUp(Event *event) { // для демонстрации события... EventMouse* e = (EventMouse*)event; string str = "Mouse Up detected, Key: "; str += tostr(e->getMouseButton()); } void MouseTest::onMouseMove(Event *event) { // для демонстрации события... EventMouse* e = (EventMouse*)event; string str = "MousePosition X:"; str = str + tostr(e->getCursorX()) + " Y:" + tostr(e->getCursorY()); } void MouseTest::onMouseScroll(Event *event) { // для демонстрации события... EventMouse* e = (EventMouse*)event; string str = "Mouse Scroll detected, X: "; str = str + tostr(e->getScrollX()) + " Y: " + tostr(e->getScrollY()); }
Создание пользовательских событий
Типы событий, описанных выше, определены системой, эти события (такие как касание экрана, нажатие клавиши и др.) обрабатываются системой автоматически. К тому же, вы можете сделать свое собственное событие, которое будет обрабатываться не системой, а вашим кодом.
_listener = EventListenerCustom::create("game_custom_event1", [=](EventCustom* event){ std::string str("Custom event 1 received, "); char* buf = static_cast<char*>(event->getUserData()); str += buf; str += " times"; statusLabel->setString(str.c_str()); }); _eventDispatcher->addEventListenerWithFixedPriority(_listener, 1);
Слушатель пользовательского события был определен с методом реакции и добавлен к диспетчеру событий. Как будет вызываться пользовательское событие? Смотрите далее:
static int count = 0; ++count; char* buf[10]; sprintf(buf, "%d", count); EventCustom event("game_custom_event1"); event.setUserData(buf); _eventDispatcher->dispatchEvent(&event);
В примере выше, мы создали объект EventCustom и задали значение UserData. Затем, событие вызывается вручную, с помощью _eventDispatcher->dispatchEvent(&event). Это запускает событие, определенное ранее. Обработчик событий вызывается непосредственно, поэтому в качестве параметра UserData, может использоваться локальная переменн��я стека.
Регистрация событий в диспетчере
Зарегистрировать событие просто. Вот пример для слушателя событий касания:
// Добавляем слушателя _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1);
Важно отметить, что событие касания может быть зарегистрировано только на один объект. Если вам необходимо использовать один слушатель для множества объектов, для этого необходимо использовать clone().
// Добавляем слушателя _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1); // Добавляем того же слушателя к другому объекту _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite2); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite3);
Удаление событий из диспетчера
Мы можем его удалить из диспетчера, следующим методом:
_eventDispatcher->removeEventListener(listener);
Хотя они могут казаться особенными, встроенные Node-объекты используют диспетчер событий тем же самым методом, о котором мы говорили. Имеет смысл, не так ли? Возьмем Menu для примера. Когда вы кликаете по элементам меню, вызывается событие. Слушатели Node-объектов также просто удалить.
От переводчика
Вот мы и закончили с основными компонентами движка! Следующие на очереди главы, в основном, очень короткие, а большую часть в них занимает один лишь пример кода. Я считаю, что неуместно будет выкладывать их по одной на Хабр. Совесть мне этого не позволит. Миксовать темы тоже не очень хорошая идея.
Но все же, я планирую опубликовать еще сколько-нибудь уроков, которые уже не будут чистыми переводами. Ниже я ос��авлю опрос, чтобы узнать что вам будет интересно. Также, можете предлагать свои варианты в комментариях.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Что еще вы хотите узнать о Cocos2d-x?
36%3D9
40%Встроенная физика объектов10
48%Скриптинг12
64%Оптимизация игры16
Проголосовали 25 пользователей. Воздержались 4 пользователя.
