cocos2d-x-3.0學習筆記之用戶事件機制

因爲cocos2d-x引擎具有跨平臺的特點,因此能夠接收並處理的事件包括觸摸事件,鍵盤事件,鼠標事件,加速度事件以及自定義事件等等。
現在的人機交互中,事件處理機制一般包括三個角色:事件、事件源和事件處理者。事件源是事件發生的場所(例如cocos裏面的node),事件接收者是接收事件並處理事件的一段程序。
1.事件
cocos提供的事件類是Event,其子類主要包括觸摸事件(EventTouch)、鼠標事件(EventMouse)、鍵盤事件(EventKeyboard)、加速度事件(EventAccleration)和自定義事件(EventCustom),其事件類圖如下:
這裏寫圖片描述

2.事件處理者
在cocos2d-x中的事件處理者是事件監聽器類EventListener。子類主要包括單點觸摸監聽器(EventListenerTouchOneByOne), 多點觸摸監聽器(EventListenerTouchAllAtOnce), 鍵盤事件監聽器(EventListenerKeyBoard), 鼠標事件監聽器(EventListenerMouse), 加速度事件監聽器(EventListenerAccleration), 自定義事件監聽器(EventListenerCustom)。其類圖如下所示:
這裏寫圖片描述
3.由上面可以看出每一種事件都與其相對應的事件監聽器綁定在一起,而這種綁定關係的過程被稱爲”註冊監聽器”。在cocos2d-x中,提供了一個事件分發器(EventDispatcher)來負責這種關係。也就是說事件監聽器負責註冊監聽器、註銷監聽器、分發事件。
EventDispatcher類是一個單例類,Director::getInstance()->getEventDispatcher()可以得到事件分發器實例。EventDispatcher有兩個註冊監聽器的函數,分別爲:

void addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node);
//這個註冊函數是將精靈顯示的優先級作爲作爲事件的優先級

void addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority);
//制定固定的的時間優先級註冊監聽器,時間的優先級決定事件的響應優先級別,
//值越小,其優先級越高

EventListenerCustom* addCustomEventListener(const std::string &eventName, const std::function<void(EventCustom*)>& callback);
//註冊一個自定義事件,第一個參數時自定義事件的名稱,
//第二個參數時響應事件的事件處理函數

4.在不需要進行事件響應時,需把先前註冊的事件監聽器給註銷掉, cocos給我們提供瞭如下幾個註銷函數

void removeEventListener(EventListener* listener);
//註銷指定的事件監聽器

void removeEventListenersForType(EventListener::Type listenerType);
//根據事件類型註銷所有的事件監聽器

void removeEventListenersForTarget(Node* target, bool recursive = false);
//根據與事件綁定的節點來註銷事件監聽器

void removeCustomEventListeners(const std::string& customEventName);
//根據事件名註銷自定義事件監聽器

void removeAllEventListeners();
//註銷所有事件監聽器,使用該函數,所有觸摸將不可用,包括菜單

二、事件運用
1.觸摸事件
EventListenerTouchOneByOne處理函數

std::function<bool(Touch*, Event*)> onTouchBegan;
//當手指剛開始觸摸時調用,返回true時調用後面的函數
std::function<void(Touch*, Event*)> onTouchMoved; 
//當手指在屏幕上移動時調用
std::function<void(Touch*, Event*)> onTouchEnded;
//當手指離開屏幕時調用
std::function<void(Touch*, Event*)> onTouchCancelled;
//當單點觸摸事件被取消時調用

EventListenerTouchAllAtOnce(多點觸控)

std::function<void(const std::vector<Touch*>&, Event*)>  onTouchesBegan;
std::function<void(const std::vector<Touch*>&, Event*)> onTouchesMoved;
std::function<void(const std::vector<Touch*>&, Event*)> onTouchesEnded;
std::function<void(const std::vector<Touch*>&, Event*)> onTouchesCancelled;

單點觸摸實例:

Scene* HelloWorld::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::create();

    // 'layer' is an autorelease object
    auto layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Point origin = Director::getInstance()->getVisibleOrigin();
    // 1. super init first
    if ( !Layer::init() )
    {
        return false;
    }

    auto labe1 = LabelBMFont::create("HelloWorld", "fonts/Roboto.bmf.fnt");
    addChild(labe1, 1);
    labe1->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2));
    labe1->setOpacity(200); //設置透明度
    // add the label as a child to this layer

    //創建一個單點觸控事件監聽器
    auto listener = EventListenerTouchOneByOne::create();
    //如果事件被處理,則吞沒該事件不繼續分發

    listener->setSwallowTouches(true);
    listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::touchBegin, this);
    listener->onTouchMoved = CC_CALLBACK_2(HelloWorld::touchMoved, this);
    listener->onTouchEnded = CC_CALLBACK_2(HelloWorld::touchEnded, this);

   //註冊監聽器
    EventDispatcher *eventDispatcher = Director::getInstance()->getEventDispatcher();
    eventDispatcher->addEventListenerWithSceneGraphPriority(listener, labe1);


    return true;
}

bool HelloWorld::touchBegin(Touch *touch, Event *event)
{
    log("touchbegin");
    return true;
}

void HelloWorld::touchMoved(Touch *touch, Event *event)
{
    log("touchmove");
}

void HelloWorld::touchEnded(Touch *touch, Event *event)
{
    log("touchend");
}

運行結果這裏寫圖片描述

在cocos3.0之後,可以使用C++11標準的lambda表達式簡化回掉代碼

//創建一個單點觸控事件監聽器
    auto listener = EventListenerTouchOneByOne::create();
    //如果事件被處理,則吞沒該事件不繼續分發

    listener->setSwallowTouches(true);
    listener->onTouchBegan = [](Touch *touch, Event *event)
    {
        log("touchbegin");
        return true;
    };
    listener->onTouchMoved = [](Touch *touch, Event *event)
    {
        log("touchmove");
    };
    listener->onTouchEnded = [](Touch *touch, Event *event)
    {
        log("touchend");
    };

   //註冊監聽器
    EventDispatcher *eventDispatcher = Director::getInstance()->getEventDispatcher();
    eventDispatcher->addEventListenerWithSceneGraphPriority(listener, labe1);

2.鍵盤事件
使用方法與單點觸控類似

std::function<void(EventKeyboard::KeyCode, Event*)> onKeyPressed;  //按鍵按下調用
std::function<void(EventKeyboard::KeyCode, Event*)> onKeyReleased; //按鍵彈起調用

3.鼠標事件

std::function<void(Event* event)> onMouseDown; //鼠標按下
std::function<void(Event* event)> onMouseUp;  //鼠標擡起
std::function<void(Event* event)> onMouseMove; //鼠標移動
std::function<void(Event* event)> onMouseScroll;//鼠標滾輪滾動

三、在層中處理觸摸
因爲層是一個特殊的節點,因此除了上述方法響應事件外,cocos還單獨爲層重寫了事件處理函數以方便調用

 virtual bool onTouchBegan(Touch *touch, Event *unused_event); 
    virtual void onTouchMoved(Touch *touch, Event *unused_event); 
    virtual void onTouchEnded(Touch *touch, Event *unused_event); 
    virtual void onTouchCancelled(Touch *touch, Event *unused_event);

    virtual void onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event);
    virtual void onTouchesMoved(const std::vector<Touch*>& touches, Event *unused_event);
    virtual void onTouchesEnded(const std::vector<Touch*>& touches, Event *unused_event);
    virtual void onTouchesCancelled(const std::vector<Touch*>&touches, Event *unused_event);

因爲層中的事件處理是針對於整個Layer,因此如果想要得到具體點擊的是Layer上的精靈,需要我們自己去判斷,而不能指定具體精靈對象的優先級。

加速度事件
加速度時間的處理與前面類似,但是也有着細微的區別,一般處理工程如下:

//啓用加速度硬件設備
    Device::setAccelerometerEnabled(true);
    //註冊監聽器
    EventDispatcher *eventDispatcher = Director::getInstance()->getEventDispatcher();
    auto listener = EventListenerAcceleration::create([](Acceleration *acc, Event *event){
        log("EventListenerAcceleration");
    });

這裏 就瞭解了cocos常用事件的處理機制,能更靈活的運用它們。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章