Implementation principle of menu response callback in cocos2dx

Source: Internet
Author: User

It seems that the cross-platform socket library on cocos2dx can only be implemented with BSD in the past few days. Asynchronous processing is required to receive push messages from the server. I have also made reference to many other people's articles. I originally wanted to have a wheel for me to use directly. It seems that I still have to make it myself. The current idea is to encapsulate a business layer, which contains a socket encapsulation. Use pthread to start a thread to select and receive data. When data arrives, call the function at the business layer to process data. The service layer registers the callback function with the interface layer, and then passes the preprocessing to the corresponding interface callback function for processing. However, I encountered a problem during compilation. When I checked the corresponding menu RESPONSE event in cocos2dx today, I realized this was the case.

In fact, this problem can be simply seen as a callback function registered with Class B in Class A. When Class A receives the corresponding event, it directly calls the callback function of Class B for processing. Originally, the callback function is a specification for the C language, because after the concept of an object exists in C ++, each member object implies a this pointer when calling it. Of course, class A does not implement callback functions of Class B, which may cause problems during compilation.

There are also many solutions on the Internet. One of the most popular solutions is to use a thunk, which is a bit high-end, this is because this pointer is implemented directly by modifying the value of the eax register through the Assembly Code. For fear of unavailability, the most troublesome thing is that you are not familiar with this, and do not know how to solve problems at that time, think about it. In fact, some people mentioned at the beginning that they could replace the called this pointer with the real owner of the callback function. At that time, they did not understand it. Now they can only find out after reading the code of cocos2dx, this is what this product is! At that time, I still thought it was amazing. It turned out to be the same method. Take ccmenuitemimage as an example.

Let's take a look at the ccmenuitem class definition:

Class cc_dll ccmenuitem: Public ccnodergba {protected:/** whether or not the item is selected @ since v0.8.2 */bool m_bselected; bool m_benabled; public: ccmenuitem (): m_bselected (false), m_benabled (false), m_plistener (null), m_pfnselector (null), m_nscripttaphandler (0) {} virtual ~ Ccmenuitem ();/** creates a ccmenuitem with no target/selector */static ccmenuitem * Create (); /** creates a ccmenuitem with a target/selector */static ccmenuitem * Create (ccobject * rec, sel_menuhandler selector ); /** initializes a ccmenuitem with a target/selector */bool initwithtarget (ccobject * rec, sel_menuhandler selector);/** returns the outside box */ccrect rect (); /** activate the item */virtual void activate ();/** the item was selected (not activated ), similar to "mouse-over" */virtual void selected ();/** the item was unselected */virtual void unselected (); /** register menu handler script function */virtual void registerscripttaphandler (INT nhandler); Virtual void unregisterscripttaphandler (void); int getscripttaphandler () {return m_nscripttaphandler ;}; virtual bool isenabled (); // @ Note: It's 'setisenable' in cocos2d-iphone. virtual void setenabled (bool value); Virtual bool isselected (); Virtual void setopacitymodifyrgb (bool bvalue) {cc_unused_param (bvalue);} virtual bool isopacitymodifyrgb (void) {return false ;} /** set the target/selector of the menu item */void settarget (ccobject * rec, sel_menuhandler selector); protected: ccobject * m_plistener; // The callback function owner sel_menuhandler m_pfnselector; // callback function int m_nscripttaphandler ;};

There are two key member variables, ccobject * m_plistener and sel_menuhandler m_pfnselector. Let's take a look at the definition of sel_menuhandler:

typedef void (CCObject::*SEL_MenuHandler)(CCObject*);#define menu_selector(_SELECTOR) (SEL_MenuHandler)(&_SELECTOR)

Yes, this is the type of the callback function, and the macro definition below is to facilitate the use of the base code.

Let's take a look at the registration code:

CCMenuItemImage * CCMenuItemImage::create(const char *normalImage, const char *selectedImage){    return CCMenuItemImage::create(normalImage, selectedImage, NULL, NULL, NULL);}CCMenuItemImage * CCMenuItemImage::create(const char *normalImage, const char *selectedImage, CCObject* target, SEL_MenuHandler selector){    return CCMenuItemImage::create(normalImage, selectedImage, NULL, target, selector);}CCMenuItemImage * CCMenuItemImage::create(const char *normalImage, const char *selectedImage, const char *disabledImage, CCObject* target, SEL_MenuHandler selector){    CCMenuItemImage *pRet = new CCMenuItemImage();    if (pRet && pRet->initWithNormalImage(normalImage, selectedImage, disabledImage, target, selector))    {        pRet->autorelease();        return pRet;    }    CC_SAFE_DELETE(pRet);    return NULL;}bool CCMenuItemImage::initWithNormalImage(const char *normalImage, const char *selectedImage, const char *disabledImage, CCObject* target, SEL_MenuHandler selector){    CCNode *normalSprite = NULL;    CCNode *selectedSprite = NULL;    CCNode *disabledSprite = NULL;    if (normalImage)    {        normalSprite = CCSprite::create(normalImage);    }    if (selectedImage)    {        selectedSprite = CCSprite::create(selectedImage);    }        if(disabledImage)    {        disabledSprite = CCSprite::create(disabledImage);    }    return initWithNormalSprite(normalSprite, selectedSprite, disabledSprite, target, selector);}

Finally, we call the following implementation callback function registration.

// Register void ccmenuitem: settarget (ccobject * rec, sel_menuhandler selector) {m_plistener = REC; m_pfnselector = selector;} // bind ccmenuitem * ccmenuitem :: create (ccobject * rec, sel_menuhandler selector) {ccmenuitem * pret = new ccmenuitem (); pret-> initwithtarget (REC, selector); pret-> initwithtarget ;} bool ccmenuitem: substring (ccobject * rec, repeated selector) {setanchorpoint (CCP (0.5f, 0.5f); m_plistener = REC; m_pfnselector = selector; m_benabled = true; m_bselected = false; return true ;}

Okay, so it's bound. It's also very simple to call. See the following code:

Void ccmenuitem: Activate () {If (m_benabled) {If (m_plistener & m_pfnselector) {(m_plistener-> * m_pfnselector) (this ); // If (kscripttypenone! = M_escripttype) {ccscriptenginemanager: sharedmanager ()-> getscriptengine ()-> executemenuitemevent (this );}}}

(M_plistener-> * m_pfnselector) (this); this sentence may be slightly explained, but it is actually quite understandable. First, this bracket is the corresponding function, and this is the parameter. This satisfies the definition of the function pointer, that is, void (ccobject: *) (ccobject *); because the ccmenuitem base class is ccobject, the actual call scenario (cscene) base class is the same. Then there is m_plistener-> * m_pfnselector, and there should be no doubt about the previous listener. The key is that * m_pfnselector may be used by some people, which is also very simple. m_pfnselector is a function pointer, first, he is a pointer and an address is stored. Then * naturally, the content in the corresponding address (the function address) is used. For function calls, it is actually an address called, m_plistener-> m_pfnselector is obviously incorrect, because the caller does not have the m_pfnselector member variable, and only the function address corresponding to the internal storage of the pointer is valid.

By the way, make it clearer to call the active code:

Void ccmenu: cctouchended (cctouch * touch, ccevent * event) {cc_unused_param (touch); cc_unused_param (event); ccassert (m_estate = kccmenustatetrackingtouch, "[menu cctouchended] -- invalid state"); If (m_pselecteditem) {m_pselecteditem-> unselected (); m_pselecteditem-> activate (); // here} m_estate = kccmenustatewaiting ;}

Cctouchended is actually a response to screen operations, and I will not post it online, so I can find it myself.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.