cocos2d-x 源碼剖析(5)

今天打開cocos2d-x的3.0-pre-alpha0 版本,突然發現裏面的變量名全變了。原來是老式的匈牙利命名法,現在的我說不出來頭,但是確實表示着代碼規範更符合現代C++的使用理念。前5篇講了下cocos2d-x程序的生命週期和主循環。現在需要深入到各個模塊中去看看細節。我們先從CCNode開始講起。

介於我的網速比較慢,我決定先生成一份本地文檔。爲了方便大家,特在此記錄下來。cocos2d-x自帶了一個document的目錄,但是裏面只有一個doxygen的配置文件。這是基於體積的考慮,如果每次將生成的文檔也包含在庫裏面的話,代碼會膨脹的相當厲害。想要生成文檔,先要下載doxygen。

其地址是:http://www.stack.nl/~dimitri/doxygen/

下載需要版本之後,安裝軟件。打開doxywizard,選擇要打開的文件爲document下的doxygen.config,然後在run頁面下點擊run doxygen便會生成一份本地的html文檔了。下面便是CCNode的繼承結構:

classcocos2d_1_1_c_c_node

 

cocos2d-x的文檔非常詳細,我認爲大家要好好學習英文,不然無法在coding界達到較高的層次。雖然開發cocos2d-x很久了,但是決定要徹查cocos2d-x之後還是發現了很多驚異之處。cocos2d-x的版本迭代實在是太快了。往往選擇一個穩定版開發之後,遊戲還沒開發完,新的穩定版又出來了。我抽出一些API來講一講,沒有特殊情況的話,大家結合文檔和源碼看,應該不難理解。畢竟我不是文檔翻譯機。

bool CCNode::init()
{
    return true;
}


曾經何時CCNode是沒有init函數的,你會發現CCNode創建出來不需要init,但是它的子節點創建出來需要init。而且init這個函數還不是virtual的。如果你是用create函數來給一個父指針賦值,當然會沒有什麼問題。但是如果你new出一個對象賦值給父指針的話,再調用init函數,卻不能得到正確的結果。這個問題存在時間之久,曾一度讓我懷疑人生,還好現在這個版本中已經修復了。

CCNode* CCNode::create(void)
{
    CCNode* pRet=newCCNode();
    if(pRet&&pRet->init())
    {
        pRet->autorelease();
    }
    else
    {
        CC_SAFE_DELETE(pRet);
    }
    returnpRet;
}


有經驗的話能一眼看出這是個static函數,我認爲這種static函數不應該加入到CCNode中去。一個Template就能搞定所有的create函數,這是典型的謀殺鍵盤行爲。而且這個函數的縮進讓人無語。

void CCNode::_setZOrder(int z)
{
    m_nZOrder = z;
}
 
void CCNode::setZOrder(int z)
{
    _setZOrder(z);
    if (m_pParent)
    {
        m_pParent->reorderChild(this, z);
    }
}


setZOrder這個函數一度讓不少新手鬱悶,誠如你看到的,原來這個公有函數設計成了_setZorder,這是沒有任何意義的,徒然增加誤解而已。現在已經修復了。

float CCNode::getVertexZ()
{
    returnm_fVertexZ;
}
 
/// vertexZ setter
void CCNode::setVertexZ(floatvar)
{
    m_fVertexZ=var;
}


這你你會覺得很奇怪,爲什麼要暴露這個接口出來。原因是ZOrder有可能被作爲一部分邏輯依賴,這時候就不單是顯示順序了。遊戲中充滿了各種例外和棘手的情況。這個函數不會改變繪製順序,但是會改變顯示層級。非必要時,不要使用。

bool CCNode::isVisible()
{
    return m_bVisible;
}
 
/// isVisible setter
void CCNode::setVisible(bool var)
{
    m_bVisible = var;
}


爲什麼要小心這個函數呢?如果你將一個Node設置爲不可見了,那麼它的子節點也會不可見,但是你如果調用它子節點的isVisible函數,它會返回一個讓你意外的結果。

const char* CCNode::description()
{
    return CCString::createWithFormat("<CCNode | Tag = %d>",
      m_nTag)->getCString();
}

這個函數要大讚,如果你函數出現了難以調試,而且是和Node相關的bug,記得還有這個函數救你一命,它能區別各個Node,不至於讓你斷到庫裏無法適從。

const CCPoint& CCNode::getAnchorPointInPoints()
{
    return m_obAnchorPointInPoints;
}

一個查漏補缺的函數。

unsigned int CCNode::getOrderOfArrival()
{
    return m_uOrderOfArrival;
}
 
void CCNode::setOrderOfArrival(unsignedintuOrderOfArrival)
{
    m_uOrderOfArrival=uOrderOfArrival;
}

爲子節點添加了ZOrder的二級調控,細化了邏輯。雖然沒有改變ZOrder,但是繪製順序改變了。Arrival就是添加進Parent的順序。先進來,先繪製,也就容易被後來的遮擋。

// override me
void CCNode::update(float fDelta)
{
    if (m_nUpdateScriptHandler)
    {
        CCScriptEngineManager::sharedManager()->getScriptEngine()->
          executeSchedule(m_nUpdateScriptHandler, fDelta, this);
    }
 
    if (m_pComponentContainer && !m_pComponentContainer->isEmpty())
    {
        m_pComponentContainer->visit(fDelta);
    }
}

這個update函數不是空,哎呦坑死爹了。重載的時候記得要調用super call啊。


CCComponent* CCNode::getComponent(const char* pName)const
{
    return m_pComponentContainer->get(pName);
}
 
bool CCNode::addComponent(CCComponent* pComponent)
{
    return m_pComponentContainer->add(pComponent);
}
 
bool CCNode::removeComponent(const char* pName)
{
    return m_pComponentContainer->remove(pName);
}
 
void CCNode::removeAllComponents()
{
    m_pComponentContainer->removeAll();
}


不知何時所加,哥要是早知道有這個東西現在就至少能少苦逼一點。我只能說這是要幹大事的節奏,期待cocos2d-x能和Unity3D分庭抗禮的那一天。詳細情況之後再分析。

CCNode作爲基礎類功能太大,今天先講到這裏,下節將按照模塊講其他內容。

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