cocos2d-x 建立自己的层级窗口消息机制-续
如果没有看过cocos2d-x 建立自己的层级窗口消息机制,请先看它,否则,下面论述你可能不知道我在说什么。
最近在学习《design patterns》的时,看到其中的decorator设计模式,就想到了自己的最近刚写的cocos2d-x 建立自己的层级窗口消息机制,并思考比较了一下。因为decorator(wrapper)模式,通过继承基类并转接基类接口来达到一个添加额外功能或者职责的目的。这个模式在书中解决这样一个问题,不用为所有的类重新派生新类来实现添加边框的功能。这正是之前的层级窗口消息机制的弊端:
//// BYTouchDelegate.cpp// TableTest//// Created by jason on 12-12-25.////#include "BYTouchDelegate.h"#include "BYUtility.h"#pragma mark- input touchebool BYTouchDelegate::byTouchBegan(CCTouch *pTouch, CCEvent *pEvent){ //pass message to all children return passMessage( m_pOwner, pTouch, pEvent );}void BYTouchDelegate::byTouchMoved(CCTouch *pTouch, CCEvent *pEvent){ //special process for menu, we won't pass ccTouchMoved message to menu. Because we think menu doesn't need ccTouchMoved message in ios device where user always want to dray layer instead menu. The fllowing block for menu will only go once. int iNumMenus = m_pMenusClaimTouch->count(); for( int i = 0; i < iNumMenus; ++i ) { ( ( CCMenu* )m_pMenusClaimTouch->objectAtIndex( i ) )->ccTouchCancelled( pTouch, pEvent ); } if( iNumMenus > 0 ) { m_pMenusClaimTouch->removeAllObjects(); } //pass ccTouchMoved message to un-CCMenu item for( int i = 0; i < m_pItemsClaimTouch->count(); ++i ) { ( ( CCLayer* )m_pItemsClaimTouch->objectAtIndex( i ) )->ccTouchMoved( pTouch, pEvent ); }}void BYTouchDelegate::byTouchEnded(CCTouch *pTouch, CCEvent *pEvent){ //for menus for( int i = 0; i < m_pMenusClaimTouch->count(); ++i ) { ( ( CCMenu* )m_pMenusClaimTouch->objectAtIndex( i ) )->ccTouchEnded( pTouch, pEvent ); } m_pMenusClaimTouch->removeAllObjects(); //for items not menu for( int i = 0; i < m_pItemsClaimTouch->count(); ++i ) { ( ( CCLayer* )m_pItemsClaimTouch->objectAtIndex( i ) )->ccTouchEnded( pTouch, pEvent ); } m_pItemsClaimTouch->removeAllObjects();}void BYTouchDelegate::byTouchCancelled(CCTouch *pTouch, CCEvent *pEvent){ //for menus for( int i = 0; i < m_pMenusClaimTouch->count(); ++i ) { ( ( CCMenu* )m_pMenusClaimTouch->objectAtIndex( i ) )->ccTouchCancelled( pTouch, pEvent ); } m_pMenusClaimTouch->removeAllObjects(); //for items not menu for( int i = 0; i < m_pItemsClaimTouch->count(); ++i ) { ( ( CCLayer* )m_pItemsClaimTouch->objectAtIndex( i ) )->ccTouchCancelled( pTouch, pEvent ); } m_pItemsClaimTouch->removeAllObjects();}bool BYTouchDelegate::passMessage( CCNode* pParent, CCTouch *pTouch, CCEvent *pEvent ){ if( !pParent || !pParent->isVisible() ) { return false; } //hande message to items int iNumChildren = 0; CCArray* pChildren = NULL; //if the item'size > 1, check whether use touches it. Such as TableView. //some items doesn't get size. they are medium for maintaining some children. Such as CCTableViewCell. if( pParent->getContentSize().width * pParent->getContentSize().height > 1.0f ) { CCPoint pt = pTouch->getLocation(); CCRect rcBoundingBox( 0, 0, pParent->getContentSize().width, pParent->getContentSize().height ); //do this only for efficiency, because convertToNodeSpace is heavier than nodeToWorldTransform(). rcBoundingBox = CCRectApplyAffineTransform( rcBoundingBox, pParent->nodeToWorldTransform() ); //whether hit the node if( !rcBoundingBox.containsPoint( pt ) ) { return false; } } pChildren = pParent->getChildren(); //no children, but user touch this item, so return true. if( !pChildren ) { return true; } iNumChildren = pParent->getChildren()->count(); //pass to all children for( int iChildIndex = 0; iChildIndex < iNumChildren; ++iChildIndex ) { //if the item claims the touch message bool bClaim = false; CCLayer* pLayer = NULL; CCNode* pNode = NULL; pNode = ( CCNode* )( pChildren->objectAtIndex( iChildIndex ) ); assert( pNode ); //if it's layer, we should invoke its ccTouchBegan()//Make sure that you have commented the CCAssertion statement in CCLayer::ccTouchBegan(). if( ( pLayer = dynamic_cast< CCLayer* >( pNode ) ) ) { bClaim = pLayer->ccTouchBegan( pTouch, pEvent ); } //pass message for its child if it doesn't derive BYTouchDelegate. Because child deriving BYTouchDelegate has passed message via ccTouchBegan(). if( !dynamic_cast< BYTouchDelegate* >( pNode ) ) { //items who doesn't derive from BYTouchDelegate can't pass touch message to its children, //so we have to help them to pass touch message. passMessage( pNode, pTouch, pEvent ); } //if this item is interested in this message, add it to array for other messages if( bClaim ) { //we don't use condition of &typeid( *pNode ) == &typeid( CCMenu ) since user may derive CCMenu. if ( dynamic_cast< CCMenu* >( pNode ) ) { m_pMenusClaimTouch->addObject( pNode ); } else { m_pItemsClaimTouch->addObject( pNode ); } } } return true;}