【cocos2dx進階】調試篇(2)Cocos2dx的一些小改造

繼續上一篇 【cocos2dx進階】調試篇(1)基礎介紹 的內容,這次主要講下對於Cocos2dx的一些小改造。


先說Cocosdx關於調試的一些設計。主要包括2塊內容,一個是log輸出,一個是節點信息的反饋。


log輸出


  • 其實核心函數是cocos2d::CCLog直接調用的話,都會輸出信息來的。這個函數提供了對平臺函數的封裝,有需要的同學可以查看相關的平臺代碼。

  • 然後,有同學想說,我的輸出需要分級,然後僅在debug下工作,於是,就有了下面這些擴展出來的宏定義

    #define __CCLOGWITHFUNCTION(s, ...) \
        CCLog("%s : %s",__FUNCTION__, CCString::createWithFormat(s, ##__VA_ARGS__)->getCString())
    // cocos2d debug
    #if !defined(COCOS2D_DEBUG) || COCOS2D_DEBUG == 0
    #define CCLOG(...)        
    #define CCLOGINFO(...)   
    #define CCLOGERROR(...)
    #define CCLOGWARN(...)   
    #elif COCOS2D_DEBUG == 1
    #define CCLOG(format, ...)      cocos2d::CCLog(format, ##__VA_ARGS__)
    #define CCLOGERROR(format,...)  cocos2d::CCLog(format, ##__VA_ARGS__)
    #define CCLOGINFO(format,...)   do {} while (0)
    #define CCLOGWARN(...) __CCLOGWITHFUNCTION(__VA_ARGS__)
    #elif COCOS2D_DEBUG > 1
    #define CCLOG(format, ...)      cocos2d::CCLog(format, ##__VA_ARGS__)
    #define CCLOGERROR(format,...)  cocos2d::CCLog(format, ##__VA_ARGS__)
    #define CCLOGINFO(format,...)   cocos2d::CCLog(format, ##__VA_ARGS__)
    #define CCLOGWARN(...) __CCLOGWITHFUNCTION(__VA_ARGS__)
    #endif // COCOS2D_DEBUG

__CCLOGWITHFUNCTION可以把當前的函數名打印出來。


節點信息


  • Cocos2dx爲了更方便的輸出調試信息,增加了description函數

    // 早期版本
    char * description();
    // 3.0 beta
    virtual std::string getDescription() const;

    配合上面的輸出函數,可以很方便的顯示相關信息



又到了吐槽環節,先來說說信息輸出的函數

  • 早期的版本,返回char*,但是引入了內存泄露,雖然是調試信息,但是總有點那啥不是。

  • description函數不是繼承的,有些類有,有些沒有,於是,好尷尬。3.0以後改了,終於那啥了。

  • description還是隻有ccnode的繼承鏈上才能用,有點限制啊,其他地方得自己動手了。

輸出函數,沒啥大問題,但是輸出依賴DEBUG定義,加了輸出看不到才發現debug宏定義不正確。


好了,不說了。開始動手改造吧。

我們知道,Cocos2dx裏面最底層的是ccobject,爲了更好的調試,我們就從這裏入手了

在ccobject類中添加函數:

#if (CC_TARGET_PLATFORM  ==  CC_PLATFORM_WIN32)
public:
        // 輸出函數
    virtual void Dump(){}
protected:
        // 格式化輸出信息
    virtual std::string dumpInfo(){return std::string();}
#endif
  • 調用Dump,用於輸出調試內容

  • dumpInfo用於Dump內部獲取需要顯示的信息


於是,我們就有了統一的調試函數Dump和用於格式化輸出的dumpInfo。這個有啥用,不就是2個函數定義麼,好吧,那我來舉個例子。

就那輸出節點信息來講吧,可以參考老G的http://4137613.blog.51cto.com/4127613/1350243

要實現這個功能,其實可以

///////////////////////////
// ccnode.h
///////////////////////////
class CC_DLL CCNode : public CCObject
{
// 略過其他,在類最下面添加
#if (CC_TARGET_PLATFORM  ==  CC_PLATFORM_WIN32)
public:
        virtual void Dump();
protected:
        void dump(int);
        virtual std::string dumpInfo();
#endif
// 結束
};

重載了ccobject中的函數

///////////////////////////
// ccnode.cpp
///////////////////////////
#if (CC_TARGET_PLATFORM  ==  CC_PLATFORM_WIN32)
void CCNode::Dump()
{
    CCLog("==================== dump ====================");
    dump(0);
    CCLog("==============================================");
}
std::string CCNode::dumpInfo()
{
    std::stringstream ss;
    ss  <<"[type]"                    <<typeid(this).name()
        <<" [tag]"                    <<getTag()
        <<" [visible]"                <<getIsVisible()
        <<" [postion]"                <<getPositionX()<<","<<getPositionY();
    return ss.str();
}
void CCNode::dump( int index)
{
    std::string info(dumpInfo());
    std::string strStruct;
    for(int i=0;i<index;++i)
        strStruct+="|   ";
    strStruct+="+ - ";
    CCLog("%s%s",strStruct.c_str(),info.c_str());
    if(m_pChildren && m_pChildren->count() > 0)
    {
        // draw children zOrder < 0
        ccArray *arrayData = m_pChildren->data;
        for(int i=0 ; i < arrayData->num; i++ )
        {
            CCNode* pNode = (CCNode*) arrayData->arr[i];
            if ( pNode)
            {
                pNode->dump(index +1);
            }
        }
    }
}
#endif

補充說明下:

  • dump( int)函數是用來遞歸調用的,index表示深度

  • typeid 是操作符,用於獲知一個變量的具體類型。VS編譯shi時需要啓用運行時類型信息和C++異常

  • 如果不滿意ccnode通用的輸出內容,可以通過重載dumpInfo,定製輸出內容

wKioL1LcubTzDjHuAALXL9xMd5o434.jpg



再來個有用的例子。

觸控操作是現在手機遊戲的主流方式。cocos2dx中也實現2種方式 targeted(單點)和standard(多點)。通過註冊handler方式,可以方便的監聽觸控事件。

設計很好,但是現實總是有點小麻煩,代碼一複雜之後,常常是觸摸了之後,函數沒有響應到,爲啥,代碼沒有錯啊,跟下吧,進入了CCTouchDispatcher.cpp之後,一陣頭暈眼花,天啊,救命……

這時候,救星來了,

//////////////////////
// CCTouchDispatcher.h
// CCTouchDispatcher類添加調試的重載函數
#if (CC_TARGET_PLATFORM  ==  CC_PLATFORM_WIN32)
    virtual void Dump();
#endif

實現


#if (CC_TARGET_PLATFORM  ==  CC_PLATFORM_WIN32)
void CCTouchDispatcher::Dump()
{
    CCLog("========= dump for CCTouchDispatcher =========");
    // optimization to prevent a mutable copy when it is not necessary
    unsigned int uTargetedHandlersCount = m_pTargetedHandlers->count();
    unsigned int uStandardHandlersCount = m_pStandardHandlers->count();
    CCLog("TargetedHandlersCount=%d",uTargetedHandlersCount);
    CCLog("StandardHandlersCount=%d",uStandardHandlersCount);
    //
    // process the target handlers 1st
    //
    if (uTargetedHandlersCount > 0)
    {
        CCLog("========= Targeted Handlers");
        CCTargetedTouchHandler *pHandler;
        CCMutableArray<CCTouchHandler*>::CCMutableArrayIterator arrayIter;
        for (arrayIter = m_pTargetedHandlers->begin(); arrayIter != m_pTargetedHandlers->end(); ++arrayIter)
        {
            pHandler = (CCTargetedTouchHandler *)(*arrayIter);
            if (! pHandler)
                break;
            CCLog("[%d]%s,SwallowsTouches=%d",pHandler->getPriority(),typeid(*(pHandler->getDelegate())).name(),pHandler->isSwallowsTouches());
        }
    }
    //
    // process standard handlers 2nd
    //
    if (uStandardHandlersCount > 0 )
    {
        CCLog("========= Standard Handlers");
        CCMutableArray<CCTouchHandler*>::CCMutableArrayIterator iter;
        CCStandardTouchHandler *pHandler;
        for (iter = m_pStandardHandlers->begin(); iter != m_pStandardHandlers->end(); ++iter)
        {
            pHandler = (CCStandardTouchHandler*)(*iter);
            if (! pHandler)
            {
                break;
            }
            CCLog("[%d]%s",pHandler->getPriority(),typeid(*(pHandler->getDelegate())).name());
                                
        }
    }
    CCLog("==============================================");
}
#endif


調用方式,在任何你需要的地方

cocos2d::CCTouchDispatcher::sharedDispatcher()->Dump();

效果如下:

wKiom1LcwAbRApMtAACN_L8muCE796.jpg



好了,剩下的,就靠大家自己發揮了。下次,是對CCLOG的一些小改造。

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