cocos2d-x CCMenu详细源码分析

cocos2d-x CCMenu详细源码分析,第1张

概述.h typedef enum { kCCMenuStateWaiting, // 表示没有菜单项被选中 kCCMenuStateTrackingTouch // 表示有菜单项被选中} tCCMenuState; enum { //* priority used by the menu for the event handler kCCMenuHandler

.h

typedef enum {    kCcmenuStateWaiting,// 表示没有菜单项被选中    kCcmenuStateTrackingtouch // 表示有菜单项被选中} tCcmenuState; enum {    //* priority used by the menu for the event handler    kCcmenuHandlerPriority = -128,}; class CC_DLL Ccmenu : public cclayerRGBA // Ccmenu的基类居然是cclayer!{    bool m_bEnabled; // Ccmenu是否接收触摸事件     public:    Ccmenu() : m_pSelectedItem(NulL) {}    virtual ~Ccmenu(){}     // 创建一个空菜单    static Ccmenu* create();     // 根据多个菜单项列创建菜单    static Ccmenu* create(CcmenuItem* item,...);     // 通过子菜单项的数组创建菜单    static Ccmenu* createWithArray(CCArray* pArrayOfItems);     // 通过一个菜单项创建菜单    static Ccmenu* createWithItem(CcmenuItem* item);         // 通过多个菜单项列创建菜单    static Ccmenu* createWithItems(CcmenuItem *firstItem,va_List args);     // 初始化空菜单    bool init();     // 通过子菜单项数组初始化菜单    bool initWithArray(CCArray* pArrayOfItems);     // 垂直方向默认间隙排列    voID alignItemsvertically();    //垂直方向指定间隙排列    voID alignItemsverticallyWithpadding(float padding);     // 水平方向默认间隙排列    voID alignItemsHorizontally();    // 水平方向指定间隙排列    voID alignItemsHorizontallyWithpadding(float padding);     // 通过每行个数排列    voID alignItemsInColumns(unsigned int columns,...);    voID alignItemsInColumns(unsigned int columns,va_List args);    // ?    voID alignItemsInColumnsWithArray(CCArray* rows);     // 通过每列个数排列    voID alignItemsInRows(unsigned int rows,...);    voID alignItemsInRows(unsigned int rows,va_List args);    // ?    voID alignItemsInRowsWithArray(CCArray* columns);     // 设置事件处理优先级,默认为kCcmenutouchPriority    voID setHandlerPriority(int newPriority);     // 基类方法    virtual voID addChild(CCNode * child);    virtual voID addChild(CCNode * child,int zOrder);    virtual voID addChild(CCNode * child,int zOrder,int tag);    virtual voID registerWithtouchdispatcher();    virtual voID removeChild(CCNode* child,bool cleanup);     // 触摸事件    virtual bool cctouchBegan(CCtouch* touch,CCEvent* event);    virtual voID cctouchended(CCtouch* touch,CCEvent* event);    virtual voID cctouchCancelled(CCtouch *touch,CCEvent* event);    virtual voID cctouchmoved(CCtouch* touch,CCEvent* event);     // 退出调用函数    virtual voID onExit();     // ?    virtual voID setopacityModifyRGB(bool bValue) {CC_UNUSED_ParaM(bValue);}    virtual bool isOpacityModifyRGB(voID) { return false;}    // 获取/设置菜单是否可用    virtual bool isEnabled() { return m_bEnabled; }    virtual voID setEnabled(bool value) { m_bEnabled = value; }; protected:    // 返回被触摸的菜单项    CcmenuItem* itemFortouch(CCtouch * touch);    tCcmenuState m_eState;    CcmenuItem *m_pSelectedItem;};
 



.cpp


static std::vector<unsigned int=""> ccarray_to_std_vector(CCArray* pArray) // 将CCArray转换成Vector{    std::vector<unsigned int=""> ret;    CCObject* pObj;    CCARRAY_FOREACH(pArray,pObj)    {        CCInteger* pInteger = (CCInteger*)pObj;        ret.push_back((unsigned int)pInteger->getValue());    }    return ret;} enum{    kDefaultpadding =  5,}; ////Ccmenu// Ccmenu* Ccmenu::create(){ // 传空参数,创建空菜单    return Ccmenu::create(NulL,NulL);} Ccmenu * Ccmenu::create(CcmenuItem* item,...){    va_List args;    va_start(args,item); //处理...形参         Ccmenu *pRet = Ccmenu::createWithItems(item,args);         va_end(args);         return pRet;} Ccmenu* Ccmenu::createWithArray(CCArray* pArrayOfItems){    Ccmenu *pRet = new Ccmenu();    if (pRet && pRet->initWithArray(pArrayOfItems))    {        pRet->autorelease(); // 设置自动释放    }    else    {        CC_SAFE_DELETE(pRet);    }         return pRet;} Ccmenu* Ccmenu::createWithItems(CcmenuItem* item,va_List args){    CCArray* pArray = NulL; // 将...形参转换成CCArray    if( item )    {        pArray = CCArray::create(item,NulL); // 创建一个CCArray        CcmenuItem *i = va_arg(args,CcmenuItem*);        while(i)        {            pArray->addobject(i); // 添加其他子菜单项            i = va_arg(args,CcmenuItem*);        }    }         return Ccmenu::createWithArray(pArray);} Ccmenu* Ccmenu::createWithItem(CcmenuItem* item){    return Ccmenu::create(item,NulL);} bool Ccmenu::init(){    return initWithArray(NulL);} bool Ccmenu::initWithArray(CCArray* pArrayOfItems){    if (cclayer::init())    {        // 设置触摸相关信息        settouchPriority(kCcmenuHandlerPriority);        settouchMode(kCCtouchesOneByOne);        settouchEnabled(true);         // 打开可用状态        m_bEnabled = true;                 // 菜单置于屏幕中间,并填充满整个屏幕        CCSize s = CCDirector::sharedDirector()->getWinSize();        this->ignoreAnchorPointForposition(true);        setAnchorPoint(ccp(0.5f,0.5f));        this->setContentSize(s);        setposition(ccp(s.wIDth/2,s.height/2));                 // 遍历添加菜单项        if (pArrayOfItems != NulL)        {            int z=0;            CCObject* pObj = NulL;            CCARRAY_FOREACH(pArrayOfItems,pObj)            {                CcmenuItem* item = (CcmenuItem*)pObj;                this->addChild(item,z);                z++;            }        }             // 将选中项置为空        m_pSelectedItem = NulL;        // 将状态置为没有菜单项被选中        m_eState = kCcmenuStateWaiting;                 // enable cascade color and opacity on menus        setCascadecolorEnabled(true);        setCascadeOpacityEnabled(true);                 return true;    }    return false;} /** overrIDe add:*/voID Ccmenu::addChild(CCNode * child){    cclayer::addChild(child);} voID Ccmenu::addChild(CCNode * child,int zOrder){    cclayer::addChild(child,zOrder);} voID Ccmenu::addChild(CCNode * child,int tag){ // 确保child为CcmenuItem之内    CCAssert( dynamic_cast<ccmenuitem*>(child) != NulL,Menu only supports MenuItem objects as children);    cclayer::addChild(child,zOrder,tag);} voID Ccmenu::onExit(){    if (m_eState == kCcmenuStateTrackingtouch) // 如果有菜单项被选中,则取消选择状态    {        if (m_pSelectedItem)        { // 将选中项菜单选中状态清除,并将用于记录的变量置为空            m_pSelectedItem->unselected();            m_pSelectedItem = NulL;        }        // 将状态置为等待触摸        m_eState = kCcmenuStateWaiting;    }     cclayer::onExit();} voID Ccmenu::removeChild(CCNode* child,bool cleanup){    CcmenuItem *pMenuItem = dynamic_cast<ccmenuitem*>(child);    CCAssert(pMenuItem != NulL,Menu only supports MenuItem objects as children);         // 如果是被选中的菜单项,则先把选中置为空    if (m_pSelectedItem == pMenuItem)    {        m_pSelectedItem = NulL;    }         CCNode::removeChild(child,cleanup);} //Menu - Events voID Ccmenu::setHandlerPriority(int newPriority){    CCtouchdispatcher* pdispatcher = CCDirector::sharedDirector()->gettouchdispatcher();    pdispatcher->setPriority(newPriority,this); // 设置触摸优先级} voID Ccmenu::registerWithtouchdispatcher(){ // 注册触摸    CCDirector* pDirector = CCDirector::sharedDirector();    pDirector->gettouchdispatcher()->addTargetedDelegate(this,this->gettouchPriority(),true);} bool Ccmenu::cctouchBegan(CCtouch* touch,CCEvent* event){    CC_UNUSED_ParaM(event);    if (m_eState != kCcmenuStateWaiting || ! m_bVisible || !m_bEnabled)    { // 排除不执行触摸事件状态        return false;    }     for (CCNode *c = this->m_pParent; c != NulL; c = c->getParent())    { // 如果菜单父类不可见则返回        if (c->isVisible() == false)        {            return false;        }    }<span >    </span>// 选出触摸项    m_pSelectedItem = this->itemFortouch(touch);    if (m_pSelectedItem)    {        m_eState = kCcmenuStateTrackingtouch; // 将状态变为有菜单项被选中        m_pSelectedItem->selected(); // 对触摸项执行触摸事件        return true;    }    return false;} 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();    }    m_eState = kCcmenuStateWaiting;} voID Ccmenu::cctouchCancelled(CCtouch *touch,CCEvent* event){    CC_UNUSED_ParaM(touch);    CC_UNUSED_ParaM(event);    CCAssert(m_eState == kCcmenuStateTrackingtouch,[Menu cctouchCancelled] -- invalID state);    if (m_pSelectedItem)    { // 解除菜单项选中状态        m_pSelectedItem->unselected();    }    m_eState = kCcmenuStateWaiting;} voID Ccmenu::cctouchmoved(CCtouch* touch,CCEvent* event){    CC_UNUSED_ParaM(event);    CCAssert(m_eState == kCcmenuStateTrackingtouch,[Menu cctouchmoved] -- invalID state);    CcmenuItem *currentItem = this->itemFortouch(touch); // 获取当前触摸的子菜单项    if (currentItem != m_pSelectedItem)     {        if (m_pSelectedItem) // 如果当前有选中项,先取消选中        {            m_pSelectedItem->unselected();        }        m_pSelectedItem = currentItem; // 重新设置选中项        if (m_pSelectedItem)        {            m_pSelectedItem->selected();        }    }} //Menu - Alignment// 垂直方向默认间隙排列voID Ccmenu::alignItemsvertically(){    this->alignItemsverticallyWithpadding(kDefaultpadding);} // 垂直方向指定间隙排列voID Ccmenu::alignItemsverticallyWithpadding(float padding){    float height = -padding;  // 第一个子菜单没有间隔,用于去掉这个重复    if (m_pChildren && m_pChildren->count() > 0)    {        CCObject* pObject = NulL;        CCARRAY_FOREACH(m_pChildren,pObject)        {            CCNode* pChild = dynamic_cast<ccnode*>(pObject);            if (pChild)            {                height += pChild->getContentSize().height * pChild->getScaleY() + padding; // 获取子菜单项和间隔的总高度            }        }    }     float y = height / 2.0f; // 因为定位点在中间,所以先除去2    if (m_pChildren && m_pChildren->count() > 0)    {        CCObject* pObject = NulL;        CCARRAY_FOREACH(m_pChildren,pObject)        {            CCNode* pChild = dynamic_cast<ccnode*>(pObject);            if (pChild)            {                pChild->setposition(ccp(0,y - pChild->getContentSize().height * pChild->getScaleY() / 2.0f)); // 锚点在中间,所以除2                y -= pChild->getContentSize().height * pChild->getScaleY() + padding; // 减去一个子菜单项和间隔的高度            }        }    }} // 水平方向默认间隙排列voID Ccmenu::alignItemsHorizontally(voID){    this->alignItemsHorizontallyWithpadding(kDefaultpadding);} // 水平方向指定间隙排列voID Ccmenu::alignItemsHorizontallyWithpadding(float padding) // 原理和垂直排列相似,只不过将x变成y{     float wIDth = -padding;    if (m_pChildren && m_pChildren->count() > 0)    {        CCObject* pObject = NulL;        CCARRAY_FOREACH(m_pChildren,pObject)        {            CCNode* pChild = dynamic_cast<ccnode*>(pObject);            if (pChild)            {                wIDth += pChild->getContentSize().wIDth * pChild->getScaleX() + padding;            }        }    }     float x = -wIDth / 2.0f;    if (m_pChildren && m_pChildren->count() > 0)    {        CCObject* pObject = NulL;        CCARRAY_FOREACH(m_pChildren,pObject)        {            CCNode* pChild = dynamic_cast<ccnode*>(pObject);            if (pChild)            {                pChild->setposition(ccp(x + pChild->getContentSize().wIDth * pChild->getScaleX() / 2.0f,0));                 x += pChild->getContentSize().wIDth * pChild->getScaleX() + padding;            }        }    }} voID Ccmenu::alignItemsInColumns(unsigned int columns,...){ // 将...转换成va_List    va_List args;    va_start(args,columns);     this->alignItemsInColumns(columns,args);     va_end(args);} voID Ccmenu::alignItemsInColumns(unsigned int columns,va_List args){ // 将va_List转换成CCArray    CCArray* rows = CCArray::create();    while (columns)    {        rows->addobject(CCInteger::create(columns));        columns = va_arg(args,unsigned int);    }    alignItemsInColumnsWithArray(rows);} voID Ccmenu::alignItemsInColumnsWithArray(CCArray* rowsArray){    vector<unsigned int=""> rows = ccarray_to_std_vector(rowsArray); // 将CCArray转换成vector     int height = -5; // 为-5是用于除去第一行的间隙    unsigned int row = 0; // 索引,当前行序号    unsigned int rowHeight = 0; // 放置每一行高度(即每行最大高度)    unsigned int columnsOccupIEd = 0; // 已放置列数    unsigned int rowColumns; // 放置该行有多少列     if (m_pChildren && m_pChildren->count() > 0) // 子菜单项数组存在且个数不为0    {        CCObject* pObject = NulL; // 临时变量        CCARRAY_FOREACH(m_pChildren,pObject) // 遍历子菜单项数组        {            CCNode* pChild = dynamic_cast<ccnode*>(pObject); // 将CCObject对象强制转换成CCNode对象            if (pChild) // 如果强制转换成功            {                CCAssert(row < rows.size(),);                 rowColumns = rows[row]; // 获取该行列数                CCAssert(rowColumns,);                 float tmp = pChild->getContentSize().height; // 获取当前子菜单高度                rowHeight = (unsigned int)((rowHeight >= tmp || isnan(tmp)) ? rowHeight : tmp); // 如果行高大于当前子菜单项高度,或者当前子菜单项高度越界,rowHeight不变,否则rowHeight等于当前子菜单项高度(用来存放最大菜单项高度)                 ++columnsOccupIEd; // 已放置列数自加                if (columnsOccupIEd >= rowColumns) // 如果已放置列数大于等于该行可容纳列数                {                    height += rowHeight + 5; // 高度加上当前高度加上间隙                    columnsOccupIEd = 0; // 重置已放置列数                    rowHeight = 0; // 重置每行行高的临时变量                    ++row; // 跳转至下一行                }            }        }    }         // check if too many rows/columns for available menu items    CCAssert(! columnsOccupIEd,);     CCSize winSize = CCDirector::sharedDirector()->getWinSize(); // 获取屏幕大小     row = 0;    rowHeight = 0;    rowColumns = 0;    float w = 0.0;    float x = 0.0;    float y = (float)(height / 2);     if (m_pChildren && m_pChildren->count() > 0)    {        CCObject* pObject = NulL;        CCARRAY_FOREACH(m_pChildren,pObject)        {            CCNode* pChild = dynamic_cast<ccnode>(pObject);            if (pChild)            {                if (rowColumns == 0) // 如果需要放置数量为0才重新读取数据                {                    rowColumns = rows[row]; // 获取需要放置的数量                    w = winSize.wIDth / (1 + rowColumns); //占屏幕宽度大小平分                    x = w;                }                 float tmp = pChild->getContentSize().height;                rowHeight = (unsigned int)((rowHeight >= tmp || isnan(tmp)) ? rowHeight : tmp); // 获取当前行高度最大高度                pChild->setposition(ccp(x - winSize.wIDth / 2,y - pChild->getContentSize().height / 2)); // 重新放置位置                 x += w;                ++columnsOccupIEd;                 if (columnsOccupIEd >= rowColumns) // 如果已放置列数大于等于需要放置的列数                {                    y -= rowHeight + 5; // 减去一个子菜单项和间隔的高度                     columnsOccupIEd = 0;                    rowColumns = 0;                    rowHeight = 0;                    ++row;                }            }        }    }    } //alignItemsInRows系列方法参照alignItemsInColumnsvoID Ccmenu::alignItemsInRows(unsigned int rows,rows);     this->alignItemsInRows(rows,args);     va_end(args);} voID Ccmenu::alignItemsInRows(unsigned int rows,va_List args){    CCArray* pArray = CCArray::create();    while (rows)    {        pArray->addobject(CCInteger::create(rows));        rows = va_arg(args,unsigned int);    }    alignItemsInRowsWithArray(pArray);} voID Ccmenu::alignItemsInRowsWithArray(CCArray* columnArray){    vector<unsigned int=""> columns = ccarray_to_std_vector(columnArray);     vector<unsigned int=""> columnWIDths;    vector<unsigned int=""> columnHeights;     int wIDth = -10;    int columnHeight = -5;    unsigned int column = 0;    unsigned int columnWIDth = 0;    unsigned int rowsOccupIEd = 0;    unsigned int columnRows;     if (m_pChildren && m_pChildren->count() > 0)    {        CCObject* pObject = NulL;        CCARRAY_FOREACH(m_pChildren,pObject)        {            CCNode* pChild = dynamic_cast<ccnode>(pObject);            if (pChild)            {                // check if too many menu items for the amount of rows/columns                CCAssert(column < columns.size(),);                 columnRows = columns[column];                // can't have zero rows on a column                CCAssert(columnRows,);                 // columnWIDth = fmaxf(columnWIDth,[item contentSize].wIDth);                float tmp = pChild->getContentSize().wIDth;                columnWIDth = (unsigned int)((columnWIDth >= tmp || isnan(tmp)) ? columnWIDth : tmp);                 columnHeight += (int)(pChild->getContentSize().height + 5);                ++rowsOccupIEd;                 if (rowsOccupIEd >= columnRows)                {                    columnWIDths.push_back(columnWIDth);                    columnHeights.push_back(columnHeight);                    wIDth += columnWIDth + 10;                     rowsOccupIEd = 0;                    columnWIDth = 0;                    columnHeight = -5;                    ++column;                }            }        }    }     // check if too many rows/columns for available menu items.    CCAssert(! rowsOccupIEd,);     CCSize winSize = CCDirector::sharedDirector()->getWinSize();     column = 0;    columnWIDth = 0;    columnRows = 0;    float x = (float)(-wIDth / 2);    float y = 0.0;     if (m_pChildren && m_pChildren->count() > 0)    {        CCObject* pObject = NulL;        CCARRAY_FOREACH(m_pChildren,pObject)        {            CCNode* pChild = dynamic_cast<ccnode>(pObject);            if (pChild)            {                if (columnRows == 0)                {                    columnRows = columns[column];                    y = (float) columnHeights[column];                }                 // columnWIDth = fmaxf(columnWIDth,[item contentSize].wIDth);                float tmp = pChild->getContentSize().wIDth;                columnWIDth = (unsigned int)((columnWIDth >= tmp || isnan(tmp)) ? columnWIDth : tmp);                 pChild->setposition(ccp(x + columnWIDths[column] / 2,y - winSize.height / 2));                 y -= pChild->getContentSize().height + 10;                ++rowsOccupIEd;                 if (rowsOccupIEd >= columnRows)                {                    x += columnWIDth + 5;                    rowsOccupIEd = 0;                    columnRows = 0;                    columnWIDth = 0;                    ++column;                }            }        }    }} CcmenuItem* Ccmenu::itemFortouch(CCtouch *touch){    CCPoint touchLocation = touch->getLocation(); // 获取当前触摸点    if (m_pChildren && m_pChildren->count() > 0) // 判断子节点(子菜单项)是否存在,且个数不为0    {        CCObject* pObject = NulL; // 临时变量        CCARRAY_FOREACH(m_pChildren,pObject) // 遍历子菜单项数组        {            CcmenuItem* pChild = dynamic_cast<ccmenuitem>(pObject); // 强制转换,获取当前子菜单项            if (pChild && pChild->isVisible() && pChild->isEnabled()) // 如果当前子菜单项不为空、且可见、且可用            {                CCPoint local = pChild->convertToNodeSpace(touchLocation); // 把世界坐标转换到当前节点的本地坐标系中                CCRect r = pChild->rect(); // 获取子菜单项范围                r.origin = CCPointZero;                if (r.containsPoint(local)) // 判断子菜单项范围中是否包括触摸点                {                    return pChild; // 返回该子菜单项                }            }        }    }    return NulL; // 返回空}


看懂了。就是知识

总结

以上是内存溢出为你收集整理的cocos2d-x CCMenu详细源码分析全部内容,希望文章能够帮你解决cocos2d-x CCMenu详细源码分析所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1002501.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)

保存