一般欲實現手機動畫大都多採用Cocos2d-x內部所提供之動畫類別來實作,此種作法比較制式化且無彈性,換言之,展現出來的動畫可能與他人大同小異,無法突顯出獨具的特色,對遊戲創造而言無引人入勝之新穎感,故自訂動畫是遊戲開發過程中必須學會之一門技巧。

此篇文章主要實現一個精靈執行載入多個圖片資源,使之達到動畫之效果(有點類似Flash技巧),將結果截取部份圖示展示如下(真實效果須於模擬器或真機上執行才能看出)
 圖片資源之原稿分別列舉如下:【此參考《捕魚達人》和《魔塔》所截錄取得】
下面動畫代碼是設計人物呈現一直走動之情況:(解析代碼並思考其運用技巧,此非我原創,是網路某位高手改寫Flash程式而來─當想用之動畫技術已有現有模組或樣式可直接套用,但要徹底分析其設計代碼學會其精髓)。

    CCTexture2D *pTexture=CCTextureCache::sharedTextureCache()->addImage("hero.png");
    CCSpriteFrame *frame0=CCSpriteFrame::createWithTexture(pTexture,CCRectMake(0,0,32,32));
    CCSpriteFrame *frame1=CCSpriteFrame::createWithTexture(pTexture,CCRectMake(32,0,32,32));
    CCSpriteFrame *frame2=CCSpriteFrame::createWithTexture(pTexture,CCRectMake(64,0,32,32));
    CCSpriteFrame *frame3=CCSpriteFrame::createWithTexture(pTexture,CCRectMake(96,0,32,32));
    CCArray  *animFrames=CCArray::create();
    CC_BREAK_IF(!animFrames);
    animFrames->addObject(frame0);
    animFrames->addObject(frame1);
    animFrames->addObject(frame2);
    animFrames->addObject(frame3);
   
    CCAnimation *animation=CCAnimation::createWithSpriteFrames(animFrames,0.2f);
   
    CC_BREAK_IF(!animation);

    CCSprite *heroSprite0=CCSprite::createWithSpriteFrame(frame0);
    CC_BREAK_IF(!heroSprite0);
    heroSprite0->setPosition(ccp(100,100));
    addChild(heroSprite0,1);
    CCAnimate *animate=CCAnimate::create(animation);
    heroSprite0->runAction(CCRepeatForever::create(animate)); //人物走動

下為另種方法實現動畫之技巧:

CCAnimation* animation2 = CCAnimation::create();

  for(int i=1;i<19;i++)
  {
    char *tt=new char[3];
    memset(tt,0,3);
    std::string s;

    if(i<10)
    {
      itoa(i,tt,10);
      s="fish00"+std::string(tt);
    }
    else
    {
      itoa(i,tt,10);
      s="fish0"+std::string(tt);
    }

    s=s+".png";

    CCTexture2D *playerRunTexture = CCTextureCache::sharedTextureCache()->addImage(s.c_str());

    animation2->addSpriteFrame(CCSpriteFrame::createWithTexture(playerRunTexture, cocos2d::CCRectMake(0, 0, 100, 100))); 

     delete []tt;
 
  }
    animation2->setDelayPerUnit(0.2f); 
    CCAnimate* action = CCAnimate::create(animation2); 
   
    CCTexture2D *playerRunTexture0 = CCTextureCache::sharedTextureCache()->addImage("fish001.png");

    CCSprite *p=CCSprite::createWithSpriteFrame(CCSpriteFrame::createWithTexture(playerRunTexture0, cocos2d::CCRectMake(0, 0, 100, 100)));
    p->setPosition(ccp(200,200));
    addChild(p,1);

    p->runAction(CCRepeatForever::create(action));

最後貼出init()函數的全部代碼供對照用:

bool HelloWorld::init()
{
  mPercentage=100;
    bool bRet = false;
    do
    {
    
    CC_BREAK_IF(! CCLayer::init());

    CCTexture2D *pTexture=CCTextureCache::sharedTextureCache()->addImage("hero.png");
    CCSpriteFrame *frame0=CCSpriteFrame::createWithTexture(pTexture,CCRectMake(0,0,32,32));
    CCSpriteFrame *frame1=CCSpriteFrame::createWithTexture(pTexture,CCRectMake(32,0,32,32));
    CCSpriteFrame *frame2=CCSpriteFrame::createWithTexture(pTexture,CCRectMake(64,0,32,32));
    CCSpriteFrame *frame3=CCSpriteFrame::createWithTexture(pTexture,CCRectMake(96,0,32,32));
    CCArray  *animFrames=CCArray::create();
    CC_BREAK_IF(!animFrames);
    animFrames->addObject(frame0);
    animFrames->addObject(frame1);
    animFrames->addObject(frame2);
    animFrames->addObject(frame3);
   
    CCAnimation *animation=CCAnimation::createWithSpriteFrames(animFrames,0.2f);
   
    CC_BREAK_IF(!animation);

    CCSprite *heroSprite0=CCSprite::createWithSpriteFrame(frame0);
    CC_BREAK_IF(!heroSprite0);
    heroSprite0->setPosition(ccp(100,100));
    addChild(heroSprite0,1);
    CCAnimate *animate=CCAnimate::create(animation);
    heroSprite0->runAction(CCRepeatForever::create(animate));//人物走動
   
    CCActionInterval *en=CCRotateBy::create(5,-360);

    CCSprite *hua=CCSprite::create("end.png");
    hua->setPosition(ccp(240,160));
    addChild(hua,1);
   
    hua->runAction(CCRepeatForever::create(en));

  CCAnimation* animation2 = CCAnimation::create();

  for(int i=1;i<19;i++)
  {
    char *tt=new char[3];
    memset(tt,0,3);
    std::string s;

    if(i<10)
    {
      itoa(i,tt,10);
      s="fish00"+std::string(tt);
    }
    else
    {
      itoa(i,tt,10);
      s="fish0"+std::string(tt);
    }

    s=s+".png";

 
    CCTexture2D *playerRunTexture = CCTextureCache::sharedTextureCache()->addImage(s.c_str());

     animation2->addSpriteFrame(CCSpriteFrame::createWithTexture(playerRunTexture, cocos2d::CCRectMake(0, 0, 100, 100))); 

     delete []tt;
 
  }

  animation2->setDelayPerUnit(0.2f); 
  CCAnimate* action = CCAnimate::create(animation2); 
   
  CCTexture2D *playerRunTexture0 = CCTextureCache::sharedTextureCache()->addImage("fish001.png");

  CCSprite *p=CCSprite::createWithSpriteFrame(CCSpriteFrame::createWithTexture(playerRunTexture0, cocos2d::CCRectMake(0, 0, 100, 100)));
  p->setPosition(ccp(200,200));
  addChild(p,1);

  p->runAction(CCRepeatForever::create(action));


        bRet = true;
    } while (0);

    return bRet;
}







此篇文章主要在分析cocos2d-x引擎底層之核心架構,其對一般作遊戲開發者而言其實不須耗費心力去啃讀,但對有志從事遊戲開發公司的程序員務必要去摸熟其來龍去脈,筆者之前也是霧煞煞瞎子摸象一陣子,過些時日有些功力再回頭看此份文件才弄懂它,雖有點深但卻是掌控遊戲之整體核心技術(※筆者一直強調學某一領域若觀念性無法handle其涵蓋之重要概念,學習過程一定跌跌撞撞又不紮實,多爬文網搜看看其他高手如何釋意後再配合看官方文件,下工夫愈深愈能展現其power)。本文參考如下網址而來,因原作者解說得不錯,故筆者予以節錄並稍加整理補充一些個人見解。
在不同平臺下其cocos2d-x的程式入口是不同的,以Win32平臺而言,主程式是由main.cpp啟始進入(類似C語言之main()方法),其底層是調用_tWinMain()函式開始著手進行後續一些必要處理程序,流程分述如下:
1.程式入口
1)在_tWinMain()中創建AppDelegate之對象 PS: AppDelegate繼承於CCApplication類,故在構造方法中初始化CCApplication單例類的唯一實例 
2)隨後,程式就完全交給了cocos2d-x引擎去處理
代碼如下:
AppDelegate app;
return cocos2d::CCApplication::sharedApplication()->run();

2.程式主迴圈
1)初始化CCEGLView,同樣地,在不同平臺下CCEGLView亦是不同 PScocos2d-x中會有很多這樣的用法,即同一個標頭檔,在不同平臺上實現也不同 ,如Win32平臺下之CCEGLView是一個作為遊戲運行之Windows視窗,其具體實現之作法為CCEGLView::Create() PSCCEGLView還可用來處理滑鼠點擊、模擬器觸摸、按鍵等事件的處理,如果要自訂,請參看CCEGLView::WindowProc(),這個函數是Windows程式接收消息回檔)。
2)遊戲引擎的主迴圈
在完成CCEGLView初始化之後,將開啟遊戲渲染(Render)的主迴圈,即調用CCDirector::sharedDirector()->mainLoop()。如此之後,程式便把執行權交給CCDirector類來處理,而此CCDirector主要處理兩件事情:
a. 通過引用計數(counter)實現對記憶體的管理(※此技術可Google看代碼之實現作法)
b. 遊戲內元素的渲染
void CCDisplayLinkDirector::mainLoop(void)
{
  if (m_bPurgeDirecotorInNextLoop)
  {
    purgeDirector();
        m_bPurgeDirecotorInNextLoop = false;
  }
  else if (! m_bInvalid)
        {
                  drawScene();
   
                  // release the objects
                  CCPoolManager::getInstance()->pop();              
        }
}
3.渲染
cocos2d中渲染的根節點是CCScenePSCCScene也是CCNode的子類),但是在drawScene()中似乎沒有類似draw()的方法,那是因為在渲染之前,要對遊戲中的節點做一些處理,包括旋轉,縮放等等,所以這個方法的名字叫visit(),而visit()是定義在CCNode中的虛方法,CCScene中並沒有單獨實現 PS:在每一次渲染的時候,都需要先將之前的矩陣載入記憶體(有人稱之為”),在渲染完當前節點之後,再由記憶體中導出矩陣,恢復之前的矩陣 
1)矩陣變化
通過CCNode::transform()對當前節點做矩陣處理(包括旋轉,縮放等等)─牽涉數學處理技巧
2)繪製
繪製就很簡單了,遍歷所有的子節點,採用遞迴的方式,對每一個CCNode調用visit()方法 PS:設置Z-Order的時候可以設置為負值,有時候是很必要的,比如我們以一個人物精靈的身體為位置參照物,繪製在Z-Order0的位置上,如果要給這個人物精靈添加一個披風耍帥,就可以將披風的Z-Order設置為負值,並且可以繼續以精靈身體作為參照物,因為cocos2d-x提供的訪問順序也是 Z-Order為負值的子節點->自身節點->Z-Order為正值的子節點──此段文字日後會再加修飾說明更詳細點)
if(m_pChildren && m_pChildren->count() > 0)
{
    // draw children zOrder < 0
        ccArray *arrayData = m_pChildren->data;
        for( ; i < arrayData->num; i++ )
        {
            pNode = (CCNode*) arrayData->arr[i];

      if ( pNode && pNode->m_nZOrder < 0 )
      {
        pNode->visit();
      }
      else
      {
        break;
      }
    }
    }

  // self draw
  this->draw();

  // draw children zOrder >= 0
    if (m_pChildren && m_pChildren->count() > 0)
    {
        ccArray *arrayData = m_pChildren->data;
        for( ; i < arrayData->num; i++ )
        {
            pNode = (CCNode*) arrayData->arr[i];
            if (pNode)
            {
                pNode->visit();
            }
    }            
  }