继续上一篇 的内容,这次主要讲下对于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 betavirtual 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的

要实现这个功能,其实可以

///// 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]"                    <
<<" [tag]" <
<<" [visible]" <
<<" [postion]" <
<<","<
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,定制输出内容

再来个有用的例子。

触控操作是现在手机游戏的主流方式。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
::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
::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();

效果如下:

好了,剩下的,就靠大家自己发挥了。下次,是对CCLOG的一些小改造。