Pull to refresh

Cocos2d-x — Диспетчер событий

Reading time 6 min
Views 6.2K

От переводчика


Доброго времени суток! Эта статья представляет собой перевод документации к движку 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-порядка(которые рисуются снизу). Это гарантирует, что события касания получат передние элементы, как и следовало ожидать.

Помните граф сцены? Когда мы говорили об этой диаграмме?

image

При использовании 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-объектов также просто удалить.

От переводчика


Вот мы и закончили с основными компонентами движка! Следующие на очереди главы, в основном, очень короткие, а большую часть в них занимает один лишь пример кода. Я считаю, что неуместно будет выкладывать их по одной на Хабр. Совесть мне этого не позволит. Миксовать темы тоже не очень хорошая идея.

Но все же, я планирую опубликовать еще сколько-нибудь уроков, которые уже не будут чистыми переводами. Ниже я оставлю опрос, чтобы узнать что вам будет интересно. Также, можете предлагать свои варианты в комментариях.
Only registered users can participate in poll. Log in, please.
Что еще вы хотите узнать о Cocos2d-x?
36% 3D 9
40% Встроенная физика объектов 10
48% Скриптинг 12
64% Оптимизация игры 16
25 users voted. 4 users abstained.
Tags:
Hubs:
+3
Comments 6
Comments Comments 6

Articles