cocos2d x 原始碼剖析(8)

2021-06-20 21:31:20 字數 4250 閱讀 2008

寫到第7節的時候,突然覺得cocos2d-x還沒有我想的那麼大啊,或許在50節以內就要了結了。這節繼續看看ccnode這個節點,主要部分是action。雖然ccnode有不少的action相關的函式,起作用的實際上是actionmanager。這節雖說是從ccnode開始,但是真正的內容在actionmanager中:

void ccnode::setactionmanager(ccactionmanager* actionmanager)} 

ccactionmanager* ccnode::getactionmanager()

ccaction * ccnode::runaction(ccaction* action)

void ccnode::stopallactions()

void ccnode::stopaction(ccaction* action)

void ccnode::stopactionbytag(int tag)

ccaction * ccnode::getactionbytag(int tag)

unsigned int ccnode::numberofrunningactions()

這種**方式簡化了ccnode本身的邏輯,很值得學習。在設計**的時候,往往不自覺的有這種意識,但是如果能清晰的認識到這樣做的優點的話,就能設計出更好**了。

我們深入到actionmanager的內部,就會發現它其實被當成是乙個單件,意外的是他沒有採用之前的那種單件模式。而且原則上沒***它必須是乙個單件不可。在ccdirector的init函式中,它被new了出來。在ccnode函式中,他被賦值給了m_pactionmanager,由於儲存了乙份本地引用,所以呼叫了retain一次,在析構的時候release了一次。

ccdirector*director=ccdirector::shareddirector();

m_pactionmanager=director->getactionmanager();

m_pactionmanager->retain();

乙份本地引用不會增加多少邏輯,但是能減少一次函式呼叫,對於頻繁使用的物件來說是值得的。而且這個actionmanager的管理方式十分有意思。在ccdirector中它被new出來之後就立馬新增到了m_pscheduler中:

// scheduler

m_pscheduler = new ccscheduler();

// action manager

m_pactionmanager = new ccactionmanager();

m_pscheduler->scheduleupdatefortarget(

m_pactionmanager, kccprioritysystem, false);

這會導致每一幀它的update都會被呼叫到:

// main loop

voidccactionmanager::update(floatdt)

m_pcurrenttarget->currentactionsalvaged=false;

m_pcurrenttarget->currentaction->step(dt);

if(m_pcurrenttarget->currentactionsalvaged)

elseif(m_pcurrenttarget->currentaction->isdone())

m_pcurrenttarget->currentaction=null;}}

// elt, at this moment, is still valid

// so it is safe to ask this here (issue #490)

elt=(thashelement*)(elt->hh.next);

// only delete currenttarget if no actions were scheduled

// during the cycle (issue #481)

if(m_bcurrenttargetsalvaged&&m_pcurrenttarget->

actions->num==0)

}// issue #635

m_pcurrenttarget=null;

}

所有被管理的action都儲存在m_ptargets中,他的宣告如下:

struct _hashelement    *m_ptargets;

typedefstruct_hashelement

thashelement;

這是乙個相對無腦的命名。可以看見actionmanager是以target為主導,來管理action的。關於縮排我就不再說什麼了。這個結構很有意思,它其實是乙個雜湊鍊錶。其內部細節我就不多做介紹了,注意這個結構的操作方式即可。

首先開始遍歷這個鍊錶,判斷target是否暫停,也就是下面這兩個函式所做的影響:

void ccactionmanager::pausetarget(ccobject *ptarget)} 

void ccactionmanager::resumetarget(ccobject *ptarget)

}

在每乙個target當中,遍歷它的action,並且呼叫它的step函式。我們注意到,在次之前有一句**比較可疑:

m_pcurrenttarget->currentactionsalvaged=false;

我們稍微想一想這句**是做什麼用的。注意進行step之後立馬就進行了判斷。那麼能對這個值做出改變的就只有step了。而且搜尋整個原始碼,能在外部改變這個值的只有removeaction介面,舉其中乙個作為例子:

void ccactionmanager::removeactionatindex(unsigned int uindex, 

thashelement *pelement)

ccarrayremoveobjectatindex(pelement->actions, uindex, true);

// update actionindex in case we are in tick.

// looping over the actions

if (pelement->actionindex >= uindex)

if (pelement->actions->num == 0)

else

}}

這個函式雖然不是外部介面,卻是核心實現。注意如果是當前action在step中被移去自己的話,那麼就會先retain一下,然後做好並將它移去,因為已經retain了一次,在從容器中刪除的時候不會析構。同理,如果刪除這個action會導致當前的節點被刪除,那麼也將這個節點標記起來。如果不是當前的節點,那就立馬刪了。注意這個操作是發生在鍊錶遍歷之中的,看看遍歷的實現就知道,移除其他節點是安全的。

由於step會導致2個意外邏輯,接下來的**就好理解了。如果當前的action被標記了,就release一次。因外被標記那時就已經從容器裡移去了,這裡要做的就是讓他析構而已。如果這個action完成了。那麼就用removeaction移去它。從上面的例子可以看到,它執行的是:

ccarrayremoveobjectatindex(pelement->actions,uindex,true);

之所以能在乙個迴圈裡面刪除資料,是因為隨後又判斷了一下,將索引減了1.

// update actionindex in case we are in tick. looping over the actions

if(pelement->actionindex>=uindex)

還乙個意外邏輯也就不難理解了,如果標記了當前的節點,並且這時候action確實為0那就刪除這個節點。之所以要再判斷一次數目,是因為step還可能新增新的action進來。

這份**的實現與之其他**相比要差很多,這恐怕也是導致action經常出bug的根源。對於actionmanager的其他函式,我想在了解了update和remove之後,其它便不難掌握了。最後還要強調一點,雖然ccnode開出了setactionmanager的介面,你如果像能正常的使用的話,還是要做不少工作的。

cocos2d x 原始碼剖析(2)

上次講到cocos2d x的main loop是下面這句 我們來看看這個函式的內部實現 return0 看看,我沒有欺騙大家吧。這個函式在設計的時候想要參照main函式返回乙個int值來表示執行結果,但是你知道的外部呼叫中完全沒有進行處理,略坑爹。來深入這個函式的內部 void startmainl...

cocos2d x 原始碼剖析(1)

原文出處 我認為在看這些文章的時候,最好有一些cocos2d x的經驗。起碼能新建乙個cocos2d x的hello world工程。而且這些文章並不是用來入門和教你如何使用cocos2d x的,我的目標是看完這些文章之後,寫乙個完整的2d引擎將沒有問題。而且能夠為cocos2d x查漏補缺,看看那...

cocos2d x 原始碼剖析(17)

draws a texture at a given point void drawatpoint const ccpoint point draws a texture inside a rect void drawinrect const ccrect rect 這節之所以單獨來講,是因為這是整...