{"id":337,"date":"2015-04-16T17:44:15","date_gmt":"2015-04-16T16:44:15","guid":{"rendered":"http:\/\/www.pixnbgames.com\/blog\/?p=337"},"modified":"2015-05-16T09:22:07","modified_gmt":"2015-05-16T08:22:07","slug":"how-to-add-event-listener-to-button-cocos2d-x-3-and-cpp","status":"publish","type":"post","link":"https:\/\/www.pixnbgames.com\/blog\/c\/how-to-add-event-listener-to-button-cocos2d-x-3-and-cpp\/","title":{"rendered":"How to add event listeners to a button in Cocos2d-x 3.x and C++"},"content":{"rendered":"<p style=\"text-align: justify;\">Recently I have started a port to iOS of my game <a title=\"Dark Snake \u2013 Android\" href=\"http:\/\/www.pixnbgames.com\/blog\/libgdx\/dark-snake-android\/\">Dark Snake<\/a>, originally made for Android. I want to take this opportunity to learn something about C++, so I have decided to use the game engine <a title=\"Cocos2d-x official site\" href=\"http:\/\/www.cocos2d-x.org\" target=\"_blank\">Cocos2d-x<\/a>. Probably, which I am going to explain in this post is trivial for a C++ developer. However, for a noob like me it has been a little headhache ^_^<\/p>\n<h2 style=\"text-align: justify;\">Basic example<\/h2>\n<p style=\"text-align: justify;\">For this example, I will supose we have got a scene named <code>MyScene<\/code>\u00a0with an only button. We need the file <em>MyScene.h<\/em>\u00a0to declare the class and <em>MyScene.cpp<\/em> to define it.<\/p>\n<h3 style=\"text-align: justify;\">MyScene.h<\/h3>\n<pre lang=\"Cpp\" line=\"1\">#ifndef __MyProject__MyScene__\r\n#define __MyProject__MyScene__\r\n\r\n#include \"cocos2d.h\"\r\n#include \"ui\/CocosGUI.h\"\r\n\r\nclass MyScene : public cocos2d::Scene {\r\npublic:\r\n    bool init();\r\n    CREATE_FUNC(MyScene);\r\n\r\n    \/\/ Callbacks\r\n    void buttonPressed();\r\n};\r\n#endif \/* defined(__MyProject__MyScene__) *\/\r\n<\/pre>\n<p style=\"text-align: justify;\">Key issues of this code:<\/p>\n<ul>\n<li style=\"text-align: justify;\">The line 4 imports the main header file of <em>cocos2d-x<\/em>. This allows us to use the main types, classes, functions and macros of <em>cocos2d-x<\/em>.<\/li>\n<li style=\"text-align: justify;\">The line 5 imports the header file of cocos2d-x in which are declared the graphics components (buttons, checkboxes, etc) to build Graphical User Interface (GUI).<\/li>\n<li style=\"text-align: justify;\">Our class extends from Scene class (defined in cocos2d).<\/li>\n<li style=\"text-align: justify;\">It&#8217;s used the macro <code>CREATE_FUNC<\/code>, defined by cocos2d. When this macro is expanded, it will generate code like this:\n<pre lang=\"Cpp\">static MyScene* create()\r\n{\r\n    MyScene *pRet = new(std::nothrow) MyScene();\r\n    if (pRet && pRet->init())\r\n    {\r\n        pRet->autorelease();\r\n        return pRet;\r\n    }\r\n    else\r\n    {\r\n        delete pRet;\r\n        pRet = NULL;\r\n        return NULL;\r\n    }\r\n}<\/pre>\n<\/li>\n<li style=\"text-align: justify;\">Looking the generated code, we see that it makes a call to a contructor which does not receive params (as we have not declared any, the compiler creates a default constructor without arguments). Furthermore, it is made a call to method <code>init()<\/code> which must return a <code>bool<\/code> value. As this method does not exist, we have to declare it at line 9.<\/li>\n<li style=\"text-align: justify;\">Finally, at line 13 is the declaration of the method which will manage the events over our button.<\/li>\n<\/ul>\n<h3 style=\"text-align: justify;\">MyScene.cpp<\/h3>\n<pre lang=\"Cpp\" line=\"1\">#include \"MyScene.h\"\r\n#include \"iostream\"\r\n\r\nusing namespace cocos2d;\r\n\r\nbool MyScene::init() {\r\n    Sprite* bg = Sprite::create(\"background.png\");\r\n    this->addChild(bg);\r\n\r\n    ui::Button* btn = ui::Button::create(\"button-image.png\");\r\n    btn->setPosition( Vec2(200.f, 200.f) );\r\n    btn->addTouchEventListener( CC_CALLBACK_0(MyScene::buttonPressed, this) );\r\n    this->addChild(btn);\r\n\r\n    return true;\r\n}\r\n\r\nvoid MyScene::buttonPressed() {\r\n    std::cout << \"PRESSED 0\" << std::endl;\r\n}\r\n<\/pre>\n<ul>\n<li style=\"text-align: justify;\">Method <code>init()<\/code> is used to add GUI components. At this instance, we only add a background image (<em>bg<\/em>) and a button (<em>btn<\/em>).<\/li>\n<li style=\"text-align: justify;\">Using <code>addTouchListener()<\/code> we get that the method <code>buttonPressed()<\/code> manages the events that button <em>btn<\/em> is going to receive.<\/li>\n<li style=\"text-align: justify;\">To indicate which method must to manage the event, we use the macro <code>CC_CALLBACK_0<\/code> passing as argument to it the selector of the method and a pointer to the object which must execute it (in this case is the current object itself, so we pass the pointer <em>this<\/em>).<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h2>Imrpoving the event listener<\/h2>\n<p style=\"text-align: justify;\">In the previous example, the method that manages the events, <code>MyScene::buttonPressed()<\/code>, does not receive any param. Nevertheless, it's possible that we need some information about the generated event, and for that purpose there are some other macros <code>CC_CALLBACK_n<\/code> defined by <em>cocos2d-x<\/em>. Some examples:<\/p>\n<h3 style=\"text-align: justify;\">Knowing the widget which has generated the event<\/h3>\n<p style=\"text-align: justify;\">suppose we want to use the same method to handle events in several graphical components, and we want to act depending on the pressed component. In this case the method for processing the events manager should receive a parameter of type <code>cocos2d::Ref*<\/code><\/p>\n<pre lang=\"Cpp\">void buttonPressed(cocos2d::Ref* pSender);<\/pre>\n<p style=\"text-align: justify;\">Param <code>pSender<\/code> is a pointer to the touched widget, and we can do a casting to the widget class in order to utilize all of its features. For example:<\/p>\n<pre lang=\"Cpp\">#define ACTION_PLAY 1\r\n\r\n.....\r\n\r\nbool MyScene::init() {\r\n    ....\r\n    ui::Button* btnPlay = ui::Button::create(\"play-image.png\");\r\n    btnPlay->setActionTag( ACTION_PLAY );\r\n    ....\r\n}\r\n.....\r\n\r\nvoid MyScene::buttonPressed(cocos2d::Ref* pSender) {\r\n    if (((cocos2d::ui::Button*) pSender)->getActionTag() == ACTION_PLAY) {\r\n        \/\/ ... do\r\n    }\r\n}<\/pre>\n<p style=\"text-align: justify;\">To link this method to a graphic component, we have to use the macro <code>CC_CALLBACK_1<\/code><\/p>\n<pre lang=\"Cpp\" line=\"1\">btn->addTouchEventListener(\r\n           CC_CALLBACK_1(MyScene::buttonPressed, this) );<\/pre>\n<p>&nbsp;<\/p>\n<h3>Knowing the type of the event<\/h3>\n<p style=\"text-align: justify;\">If we test the event managers showed previously, we get two events for each touch on the button. This is beacuse an event is generated when the button is pressed, and another event is generated when the button is released. To know what type of event has been generated, we can use a method which receives a param of type <code>TouchEventType<\/code>:<\/p>\n<pre lang=\"Cpp\">void buttonPressed(cocos2d::Ref *pSender, cocos2d::ui::Widget::TouchEventType eventType);<\/pre>\n<p style=\"text-align: justify;\">The <code>TouchEventType<\/code> object is an enum that can has the values <code>BEGAN<\/code>, <code>MOVED<\/code>, <code>ENDED<\/code> o <code>CANCELED<\/code>. If we want to proceed, for example, only when the button is pressed, we must do something like this:<\/p>\n<pre lang=\"Cpp\">void MyScene::buttonPressed(cocos2d::Ref *pSender, cocos2d::ui::Widget::TouchEventType eventType) {\r\n    if (cocos2d::ui::Widget::TouchEventType::BEGAN == eventType) {\r\n        \/\/ ... do\r\n    }\r\n}<\/pre>\n<p style=\"text-align: justify;\">To link this method with a graphic component, we have to use the macro <code>CC_CALLBACK_2<\/code><\/p>\n<pre lang=\"Cpp\" line=\"1\">btn->addTouchEventListener(\r\n          CC_CALLBACK_2(MyScene::buttonPressed, this) );<\/pre>\n<p>&nbsp;<\/p>\n<p>I hope this post is helpful for you.<\/p>\n<p>Regards!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently I have started a port to iOS of my game Dark Snake, originally made for Android. I want to take this opportunity to learn something about C++, so I have decided to use the game engine Cocos2d-x. Probably, which <a class=\"more-link\" href=\"https:\/\/www.pixnbgames.com\/blog\/c\/how-to-add-event-listener-to-button-cocos2d-x-3-and-cpp\/\">Seguir leyendo <span class=\"screen-reader-text\">  How to add event listeners to a button in Cocos2d-x 3.x and C++<\/span><span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[28,29],"tags":[31,32,30,25,35],"language":[4],"_links":{"self":[{"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/posts\/337"}],"collection":[{"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/comments?post=337"}],"version-history":[{"count":20,"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/posts\/337\/revisions"}],"predecessor-version":[{"id":358,"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/posts\/337\/revisions\/358"}],"wp:attachment":[{"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/media?parent=337"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/categories?post=337"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/tags?post=337"},{"taxonomy":"language","embeddable":true,"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/language?post=337"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}