1. 程式人生 > >Cocos2d-x 2.0 之 Actions “三板斧” 之三

Cocos2d-x 2.0 之 Actions “三板斧” 之三

[Cocos2d-x相關教程來源於紅孩兒的遊戲程式設計之路CSDN部落格地址:http://blog.csdn.net/honghaier]

紅孩兒Cocos2d-X學習園地QQ2群:44208467 加群寫:Cocos2d-x 
紅孩兒Cocos2d-X學習園地QQ群:249941957 [暫滿]加群寫:Cocos2d-x 

本章為我的Cocos2d-x教程一書初稿。望各位看官多提建議!

Cocos2d-x 2.0 TestCpp 之 ActionsTest深入分析

另:本章所用Cocos2d-x版本為:

  之前兩斧子,相信大家已經對於動畫的原理有了比較清楚的瞭解,這最後一斧子,咱們一起看一看ActionsTest.h

cpp。我們開啟標頭檔案來看一下程式碼:

#ifndef _ActionsTest_H_
#define _ActionsTest_H_
//包含示例的基本標頭檔案,因為要用到演示場景基類TestScene。這個類在之前的TestCpp框架分析中有講解。
#include "../testBasic.h"
////----#include "cocos2d.h"
//使用Cocos2d的名稱空間
USING_NS_CC;
//這裡是一個列舉,列出了示例中所有的精靈動畫型別
enum
{
    ACTION_MANUAL_LAYER = 0,//基本狀態
    ACTION_MOVE_LAYER,		//移動動畫
    ACTION_SCALE_LAYER,		//縮放動畫
    ACTION_ROTATE_LAYER,		//旋轉動畫
    ACTION_SKEW_LAYER,		//扭曲動畫
    ACTION_SKEWROTATE_LAYER,//扭曲與旋轉組合動畫
    ACTION_JUMP_LAYER,		//跳躍動畫
    ACTION_CARDINALSPLINE_LAYER,//貝塞爾曲線動畫
    ACTION_CATMULLROM_LAYER,//點構成的曲線動畫
    ACTION_BEZIER_LAYER,		//貝塞爾曲線路徑動畫
    ACTION_BLINK_LAYER,		//閃現動畫
    ACTION_FADE_LAYER,		//淡入淡出動畫
    ACTION_TINT_LAYER,		//變色動畫
    ACTION_ANIMATE_LAYER,	//幀動畫
    ACTION_SEQUENCE_LAYER,	//動畫序列
    ACTION_SEQUENCE2_LAYER,	//動畫序列
    ACTION_SPAWN_LAYER,		//動畫組合
    ACTION_REVERSE,			//反向播放動畫
    ACTION_DELAYTIME_LAYER,	//動畫暫停與繼續播放
    ACTION_REPEAT_LAYER,		//重複播放動畫
    ACTION_REPEATEFOREVER_LAYER,//無限迴圈播放動畫
    ACTION_ROTATETOREPEATE_LAYER,//迴圈旋轉動畫一
    ACTION_ROTATEJERK_LAYER,//迴圈旋轉動畫二
    ACTION_CALLFUNC_LAYER,//動畫與函式呼叫一
    ACTION_CALLFUNCND_LAYER,//動畫與函式呼叫二
    ACTION_REVERSESEQUENCE_LAYER,//反向動畫序列。
    ACTION_REVERSESEQUENCE2_LAYER,//反向動畫序列二。
    ACTION_ORBIT_LAYER,//旋轉攝像機動畫
    ACTION_FLLOW_LAYER,//跟隨動畫
    ACTION_TARGETED_LAYER,//控制目標動畫
    PAUSERESUMEACTIONS_LAYER,//暫停與恢復動畫
    ACTION_ISSUE1305_LAYER,//1305號動畫
    ACTION_ISSUE1305_2_LAYER,//1305號的動畫二
    ACTION_ISSUE1288_LAYER,//1288號動畫
    ACTION_ISSUE1288_2_LAYER,//1288的動畫二
    ACTION_ISSUE1327_LAYER,//1327號動畫
    ACTION_LAYER_COUNT,//動畫最大數量
};

//看完這些列舉,我想說的是,精靈動畫的型別真TMD豐富啊!竟然多到想不出名字~:)

//這是用於展示每種動畫的基礎場景類,它包含了一個返回主選單的按鈕。
class ActionsTestScene : public TestScene
{
public:
	//重虛擬函式runThisTest做一些初始化工作。
    virtual void runThisTest();
};
為了方便程式碼閱讀,我將CPP中相應函式實現移過來,後面都按這種格式:
//演示動畫所用場景基類的初始化函式過載
void ActionsTestScene::runThisTest()
{
	//先將索引置-1,後面呼叫NextAction()使其加1變為0,即演示第一個動畫。
    s_nActionIdx = -1;
    addChild(NextAction());
	//運行當前場景。
    CCDirector::sharedDirector()->replaceScene(this);
}



//從CCLayer派生出一個基礎的動畫演示類,用於包含要表現動作的一些精靈。
class ActionsDemo : public CCLayer
{
protected:
	//動畫的主角要出場啦!以下是三個圖片精靈例項指標,其分別指向出場表演的男1號grossini,女1號tamara,女2號kathia,這一男兩女將成為動畫演示的三位演員。大家歡迎它們!
    CCSprite*    m_grossini;
    CCSprite*    m_tamara;
    CCSprite*    m_kathia;
public:
	//過載當前動畫類被載入時要呼叫的函式onEnter做一些精靈生成的處理。
    virtual void onEnter();
	//過載當前動畫類被解除安裝時要呼叫的函式onExit做一些釋放處理。
    virtual void onExit();
	//這個函式用於指定需要幾位演員出場時如果要求居中對齊該怎麼站位。
    void centerSprites(unsigned int numberOfSprites);
	//這個函式用於指定需要幾位演員出場時如果要求居左對齊該怎麼站位。
    void alignSpritesLeft(unsigned int numberOfSprites);
	//取得動畫的主標題
    virtual std::string title();
	//取得動畫的副標題
    virtual std::string subtitle();
	//當在點選“重置”按鈕時的回撥函式
    void restartCallback(CCObject* pSender);
	//當在點選“下一個”按鈕時的回撥函式
    void nextCallback(CCObject* pSender);
	//當在點選“上一個”按鈕時的回撥函式。
    void backCallback(CCObject* pSender);
};
//取得演示動畫CCLayer所用基類的主標題
std::string ActionsDemo::title()
{
    return "ActionsTest";
}
//取得演示動畫CCLayer所用基類的副標題
std::string ActionsDemo::subtitle()
{
    return "";
}
//載入演示動畫CCLayer所用基類時的初始化處理函式。
void ActionsDemo::onEnter()
{
    CCLayer::onEnter();

	//建立了三個演員。
	//男一號,其使用圖片地址為s_pPathGrossini
    m_grossini = CCSprite::create(s_pPathGrossini);
    m_grossini->retain();

	//女一號,其使用圖片地址為s_pPathSister1
    m_tamara = CCSprite::create(s_pPathSister1); 
	m_tamara->retain();
	
	//女二號,其使用圖片地址為s_pPathSister2
    m_kathia = CCSprite::create(s_pPathSister2);
	m_kathia->retain();
	
	//將三位演員都放入當前演示動畫所在的CCLayer中。
    addChild(m_grossini, 1);
    addChild(m_tamara, 2);
    addChild(m_kathia, 3);
	//取得螢幕的大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
	//男一號站在螢幕中下位置
	m_grossini->setPosition(CCPointMake(s.width/2, s.height/3));
	//女一號站在螢幕中上位置
	m_tamara->setPosition(CCPointMake(s.width/2, 2*s.height/3));
	//女二號站在螢幕正中間
    m_kathia->setPosition(CCPointMake(s.width/2, s.height/2)); 

    // 建立一個文字標籤用於顯示標題
    std::string str = title();
    const char * pTitle = str.c_str();
    CCLabelTTF* label = CCLabelTTF::create(pTitle, "Arial", 18);
    addChild(label, 1);
	//將文字標籤放在螢幕正中靠上位置
    label->setPosition( CCPointMake(s.width/2, s.height - 30) );
	//建立一個文字標籤用於顯示副標題
    std::string strSubtitle = subtitle();
    if( ! strSubtitle.empty() ) 
    {
		//建立檔案標籤並放在主標題文字標籤之下。
        CCLabelTTF* l = CCLabelTTF::create(strSubtitle.c_str(), "Thonburi", 22);
        addChild(l, 1);
        l->setPosition( CCPointMake(s.width/2, s.height - 60) );
    }    

    // 建立三個按鈕(看名字應理解為圖片選單項,其實就是具有普通和按下兩種狀態的圖片切換效果的按鈕)用於控制演示的動畫。
	// 第一個按鈕,在按下時呼叫演示上一個動畫的函式。
    CCMenuItemImage *item1 = CCMenuItemImage::create(s_pPathB1, s_pPathB2, this, menu_selector(ActionsDemo::backCallback) );
	// 第二個按鈕,在按下時呼叫重新演示當前動畫的函式。
    CCMenuItemImage *item2 = CCMenuItemImage::create(s_pPathR1, s_pPathR2, this, menu_selector(ActionsDemo::restartCallback) );
	// 第三個按鈕,在按下時呼叫演示下一個動畫的函式。
    CCMenuItemImage *item3 = CCMenuItemImage::create(s_pPathF1, s_pPathF2, this, menu_selector(ActionsDemo::nextCallback) );
	//由這三個按鈕(也就是剛說的“圖片選單項”)生成一個選單。因為CMenuItemImage和CCMenu都是CCNode的子類。所以這一句本質上是將若干CCNode做為一個新的CCNode的子節點並返回。
    CCMenu *menu = CCMenu::create(item1, item2, item3, NULL);
	//將選單放在零零點位置。
    menu->setPosition(CCPointZero);
	//設定各個按鈕相對於選單項的位置。
    item1->setPosition(CCPointMake(s.width/2 - item2->getContentSize().width*2, item2->getContentSize().height/2));
    item2->setPosition(CCPointMake(s.width/2, item2->getContentSize().height/2));
    item3->setPosition(CCPointMake(s.width/2 + item2->getContentSize().width*2, item2->getContentSize().height/2));
	//將選單加入當前的演示動畫CCLayer所用基類中。
    addChild(menu, 1);
}
//在當前演示動畫CCLayer所用基類被釋放時的處理函式
void ActionsDemo::onExit()
{
	//精靈的釋放,代表三位演員的退場。
    m_grossini->release();
    m_tamara->release();
    m_kathia->release();

    CCLayer::onExit();
}
//重新演示當前動畫的回撥函式。
void ActionsDemo::restartCallback(CCObject* pSender)
{
	//建立一個新場景
    CCScene* s = new ActionsTestScene();
	//將RestartAction()函式返回的CCLayer加入場景中。
    s->addChild( RestartAction() );
	//將新場景做為遊戲要顯示的場景。
    CCDirector::sharedDirector()->replaceScene(s);
	//引用計數器減1操作,以使未來可以正確的被釋放。
    s->release();
}
//演示下一個動畫的回撥函式。
void ActionsDemo::nextCallback(CCObject* pSender)
{
	//建立一個新場景
    CCScene* s = new ActionsTestScene();
	//將NextAction()函式返回的CCLayer加入場景中。
    s->addChild( NextAction() );
	//將新場景做為遊戲要顯示的場景。
    CCDirector::sharedDirector()->replaceScene(s);
	//引用計數器減1操作,以使未來可以正確的被釋放。
    s->release();
}
//演示上一個動畫的回撥函式。
void ActionsDemo::backCallback(CCObject* pSender)
{
	//建立一個新場景
    CCScene* s = new ActionsTestScene();
	//將BackAction ()函式返回的CCLayer加入場景中。
    s->addChild( BackAction() );
	//將新場景做為遊戲要顯示的場景。
    CCDirector::sharedDirector()->replaceScene(s);
	//引用計數器減1操作,以使未來可以正確的被釋放。
    s->release();
}
//這個函式用於指定需要幾位演員出場時如果要求居中對齊該怎麼站位。
void ActionsDemo::centerSprites(unsigned int numberOfSprites)
{
	//取得螢幕大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    if( numberOfSprites == 0 )
    {	//如果指定沒有演員,將三位演員都設為不顯示
        m_tamara->setVisible(false);
        m_kathia->setVisible(false);
        m_grossini->setVisible(false);
    } 
    else if ( numberOfSprites == 1 ) 
    {	//如果指定只有一位演員來表演,則將男一號放在螢幕中央,兩位女演員設為不顯示。
        m_tamara->setVisible(false);
        m_kathia->setVisible(false);
        m_grossini->setPosition(CCPointMake(s.width/2, s.height/2));
    }
    else if( numberOfSprites == 2 ) 
    {   //如果指定兩位演員來表演,則將兩位女演員放在螢幕中心位置對齊的兩邊,並將男演員設為不顯示。     
        m_kathia->setPosition( CCPointMake(s.width/3, s.height/2));
        m_tamara->setPosition( CCPointMake(2*s.width/3, s.height/2));
        m_grossini->setVisible(false);
    } 
    else if( numberOfSprites == 3 ) 
    {	//三位演員同時上場,分別放在螢幕左,中,右三個位置。
        m_grossini->setPosition( CCPointMake(s.width/2, s.height/2));
        m_tamara->setPosition( CCPointMake(s.width/4, s.height/2));
        m_kathia->setPosition( CCPointMake(3 * s.width/4, s.height/2));
    }
}
//這個函式用於指定需要幾位演員出場時如果要求居左對齊該怎麼站位。同上,只是位置略有差別。
void ActionsDemo::alignSpritesLeft(unsigned int numberOfSprites)
{
    CCSize s = CCDirector::sharedDirector()->getWinSize();

    if( numberOfSprites == 1 ) 
    {
        m_tamara->setVisible(false);
        m_kathia->setVisible(false);
        m_grossini->setPosition(CCPointMake(60, s.height/2));
    } 
    else if( numberOfSprites == 2 ) 
    {        
        m_kathia->setPosition( CCPointMake(60, s.height/3));
        m_tamara->setPosition( CCPointMake(60, 2*s.height/3));
        m_grossini->setVisible( false );
    } 
    else if( numberOfSprites == 3 ) 
    {
        m_grossini->setPosition( CCPointMake(60, s.height/2));
        m_tamara->setPosition( CCPointMake(60, 2*s.height/3));
        m_kathia->setPosition( CCPointMake(60, s.height/3));
    }
}



//這是第一個要演示的動畫,其實它只是把三位演員顯示出來。
class ActionManual : public ActionsDemo
{
public:
	//過載當前動畫類被載入時要呼叫的函式onEnter做一些精靈生成的處理。
    virtual void onEnter();
	//過載取得動畫的副標題
    virtual std::string subtitle();
};
//基礎演示動畫所用CCLayer被載入時的初始化處理函式。
void ActionManual::onEnter()
{	//呼叫基類的同名函式,載入三位演員。
    ActionsDemo::onEnter();
	//取得螢幕的大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
	//將女一號演員在X,Y方向上分別縮放後放在相應位置,並設定其半透明。
    m_tamara->setScaleX( 2.5f);
    m_tamara->setScaleY( -1.0f);
    m_tamara->setPosition( CCPointMake(100,70) );
	//透明度的取值為0~255,0代表完全透明,255代表完全不透明。
    m_tamara->setOpacity( 128);

	//男一號演員,這裡讓它旋轉120度之後放在螢幕中心位置,並設定其全身顏色為紅色。
    m_grossini->setRotation( 120);
    m_grossini->setPosition( CCPointMake(s.width/2, s.height/2));
	//色彩設定為紅色。ccc3分別用R,G,B三元色做為引數返回色彩值。
    m_grossini->setColor( ccc3( 255,0,0));
	//女二號演員,這裡設定位置為螢幕中心靠左。
    m_kathia->setPosition( CCPointMake(s.width-100, s.height/2));
	//色彩設定為藍色,這以用預定義的巨集ccBLUE來代表藍色的色彩值。
    m_kathia->setColor( ccBLUE);
}
//取得當前演示動畫的副標題。
std::string ActionManual::subtitle()
{
    return "Manual Transformation";
}


//第二種動畫演示表現了三位演員的移動變化。
class ActionMove : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
//移動動畫所用CCLayer被載入時的初始化處理函式。
void ActionMove::onEnter()
{	//呼叫基類的同名函式,載入三位演員。
    ActionsDemo::onEnter();
	//讓三位演員以居中對齊方式進行站位。
    centerSprites(3);
	//取得螢幕的大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
	//建立三個時間漸變動畫。第一個是由CCActionInterval子類CCMoveTo靜態函式所建立的“2秒移動到某位置”,第二個是由CCActionInterval子類CCMoveTo靜態函式所建立的“2秒移動多少距離”。第三個是第二個動畫的反向播放。
    CCActionInterval*  actionTo = CCMoveTo::create(2, CCPointMake(s.width-40, s.height-40));
    CCActionInterval*  actionBy = CCMoveBy::create(2, CCPointMake(80,80));
    CCActionInterval*  actionByBack = actionBy->reverse();
	//讓三個演員分別按照不同的動畫形式來演示。女一號就按第一種動畫來進行演示。
    m_tamara->runAction( actionTo);
	//男一號呢?它的演示是第二個動畫和第三個動畫的串聯。CCSequence::create函式可以將多個動畫串聯在一起,按照串聯的順序進行逐個播放。
    m_grossini->runAction( CCSequence::create(actionBy, actionByBack, NULL));
	//女二號同女一號類似也是演示一個移動到某位置的動畫。這裡指定1秒內移動到40,40的位置。
    m_kathia->runAction(CCMoveTo::create(1, CCPointMake(40,40)));
}
//這裡取得移動動畫演示的副標題。
std::string ActionMove::subtitle()
{
    return "MoveTo / MoveBy";
}

//第三種動畫演示表現了三位演員的縮放變化。
class ActionScale : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
//縮放動畫演示
void ActionScale::onEnter()
{	
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//將三個演員按居中對齊進行站位
    centerSprites(3);
	//三個要演示的動畫形式分別是
	//1.縮放到指定的程度
    CCActionInterval*  actionTo = CCScaleTo::create(2.0f, 0.5f);
	//2.當前縮放值再續繼縮放多少
    CCActionInterval*  actionBy = CCScaleBy::create(2.0f, 1.0f, 10.0f);
	//3.同2
    CCActionInterval*  actionBy2 = CCScaleBy::create(2.0f, 5.0f, 1.0f);
	//讓男一號演示動畫1
    m_grossini->runAction( actionTo);
	//讓女一號演示一個動畫序列,這個序列為先演示動畫2,再演示動畫2的反向播放。
    m_tamara->runAction( CCSequence::create(actionBy, actionBy->reverse(), NULL));
	//女二號的動畫同女一號
    m_kathia->runAction( CCSequence::create(actionBy2, actionBy2->reverse(), NULL));
}
//副標題
std::string ActionScale::subtitle()
{
    return "ScaleTo / ScaleBy";
}

//第四種動畫演示表現了三位演員的旋轉變化
class ActionRotate : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionRotate::onEnter()
{
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//將三個演員按居中對齊進行站位
    centerSprites(3);
	//定義幾種旋轉到某個角度的動畫
    CCActionInterval*  actionTo = CCRotateTo::create( 2, 45);
    CCActionInterval*  actionTo2 = CCRotateTo::create( 2, -45);
    CCActionInterval*  actionTo0 = CCRotateTo::create(2 , 0);
	//女一號演示一個動畫序列
    m_tamara->runAction( CCSequence::create(actionTo, actionTo0, NULL));
	//定義從現在的角度在2秒內繼續旋轉360度的動畫
    CCActionInterval*  actionBy = CCRotateBy::create(2 ,  360);
	//定義actionBy的反向播放動畫
    CCActionInterval*  actionByBack = actionBy->reverse();
	//男一號演示一個動畫序列
    m_grossini->runAction( CCSequence::create(actionBy, actionByBack, NULL));
	//女二號演示一個動畫序列,這個動畫序列中有一個動畫為actionTo0的拷貝,並將這個拷貝設為由記憶體管理器進行記憶體釋放。這句裡有兩個知識點:(1)為什麼要使用動畫的拷貝?(2)為什麼要呼叫autorelease?答案分別是:(1)目前的引擎機制要求每個動畫只能有一個演員使用。當你呼叫runAction時會將動畫加入動畫管理器,而動畫管理器呼叫addAction函式時,會在最後呼叫pAction->startWithTarget(pTarget);如果這個動畫已經有一個演員在使用了,這裡會覆蓋掉之前的演員資訊,動畫只能被最後使用的演員佔有。(2)因為create函式建立動畫時,會在內部對動畫呼叫autorelease,而copy函式只會新生成一個動畫的複製品,不會對其進行呼叫autorelease。
    m_kathia->runAction( CCSequence::create(actionTo2, actionTo0->copy()->autorelease(), NULL));
}
//顯示副標題
std::string ActionRotate::subtitle()
{
    return "RotateTo / RotateBy";
}

//第五種動畫演示表現了三位演員的扭曲變化。
class ActionSkew : public ActionsDemo
{
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionSkew::onEnter()
{	
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//將三個演員按居中對齊進行站位
    centerSprites(3);
	//這裡定義了五種動畫
	//前兩種動畫是扭曲到指定程度
    CCActionInterval *actionTo = CCSkewTo::create(2, 37.2f, -37.2f);
    CCActionInterval *actionToBack = CCSkewTo::create(2, 0, 0);
	//然後兩種動畫是繼續扭曲多少
    CCActionInterval *actionBy = CCSkewBy::create(2, 0.0f, -90.0f);
    CCActionInterval *actionBy2 = CCSkewBy::create(2, 45.0f, 45.0f);
	//最後一種動畫是actionBy的反向播放
    CCActionInterval *actionByBack = actionBy->reverse();
	//女一號演示一個動畫序列,這個動畫序列有兩個動畫,先是actionTo,然後是actionToBack
    m_tamara->runAction(CCSequence::create(actionTo, actionToBack, NULL));
	//男一號演示一個動畫序列,這個動畫序列有兩個動畫,先是actionBy,然後是actionByBack
    m_grossini->runAction(CCSequence::create(actionBy, actionByBack, NULL));
	//女二號演示一個動畫序列,這個動畫序列也是有兩個動畫,先是actionBy2,然後是它的反向播放。
    m_kathia->runAction(CCSequence::create(actionBy2, actionBy2->reverse(), NULL));
}
//副標題
string ActionSkew::subtitle()
{
    return "SkewTo / SkewBy";
}

//第六種動畫演示表現的是前面幾種變化的大雜燴。
class ActionSkewRotateScale : public ActionsDemo
{
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionSkewRotateScale::onEnter()
{
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//本動畫用不到三位演員,在此將它們刪除
    m_tamara->removeFromParentAndCleanup(true);
    m_grossini->removeFromParentAndCleanup(true);
    m_kathia->removeFromParentAndCleanup(true);
	//這裡取得一個寬高均為100的大小
    CCSize boxSize = CCSizeMake(100.0f, 100.0f);
	//建立一個顏色層
    CCLayerColor *box = CCLayerColor::create(ccc4(255, 255, 0, 255));
	//設定錨點為左下角
    box->setAnchorPoint(ccp(0, 0));
	//設定當前顏色層的位置
    box->setPosition(ccp(190, 110));
	//設定顏色色的大小
    box->setContentSize(boxSize);
	//在顏色層上再加立兩個子顏色層。
	//第一個是紅色,放在左上角。
    static float markrside = 10.0f;
    CCLayerColor *uL = CCLayerColor::create(ccc4(255, 0, 0, 255));
    box->addChild(uL);
    uL->setContentSize(CCSizeMake(markrside, markrside));
    uL->setPosition(ccp(0.f, boxSize.height - markrside));
    uL->setAnchorPoint(ccp(0, 0));
	//第二個是藍色,放在右上角。
    CCLayerColor *uR = CCLayerColor::create(ccc4(0, 0, 255, 255));
    box->addChild(uR);
    uR->setContentSize(CCSizeMake(markrside, markrside));
    uR->setPosition(ccp(boxSize.width - markrside, boxSize.height - markrside));
    uR->setAnchorPoint(ccp(0, 0));
    addChild(box);
	//定義幾種動畫,分別為扭曲,旋轉,縮放。
    CCActionInterval *actionTo = CCSkewTo::create(2, 0.f, 2.f);
    CCActionInterval *rotateTo = CCRotateTo::create(2, 61.0f);
    CCActionInterval *actionScaleTo = CCScaleTo::create(2, -0.44f, 0.47f);

    CCActionInterval *actionScaleToBack = CCScaleTo::create(2, 1.0f, 1.0f);
    CCActionInterval *rotateToBack = CCRotateTo::create(2, 0);
    CCActionInterval *actionToBack = CCSkewTo::create(2, 0, 0);
	//讓顏色層同時演示三個動畫序列。這裡要理解為什麼它可以同時演示多個動畫序列?我們之前將過runAction會將演員和動畫通知動畫管理器,這些動畫會存入相應的動畫集,動畫管理器在每幀會更新相應的動畫,這裡雖然用的是動畫序列,但是動畫序列本身仍然是動畫。所以呼叫多次runAction可以將多個動畫或動畫序列同時播放。
    box->runAction(CCSequence::create(actionTo, actionToBack, NULL));
    box->runAction(CCSequence::create(rotateTo, rotateToBack, NULL));
    box->runAction(CCSequence::create(actionScaleTo, actionScaleToBack, NULL));
}
//取得副標題。
string ActionSkewRotateScale::subtitle()
{
    return "Skew + Rotate + Scale";
}

//第七種動畫演示表現的是如何讓演員們按照拋物線跳躍。
class ActionJump : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionJump::onEnter()
{
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//將三個演員按居中對齊進行站位
    centerSprites(3);
	//定義一個動畫,代表跳躍到某個位置
    CCActionInterval*  actionTo = CCJumpTo::create(2, CCPointMake(300,300), 50, 4);
	//定義一個動畫,代表從現在的位置跳躍多遠距離。
    CCActionInterval*  actionBy = CCJumpBy::create(2, CCPointMake(300,0), 50, 4);
	//定義一個只是向上跳的動畫
    CCActionInterval*  actionUp = CCJumpBy::create(2, CCPointMake(0,0), 80, 4);
	//定義第二個動畫的反向播放動畫
    CCActionInterval*  actionByBack = actionBy->reverse();
	//三位演員分別執行相應動畫。
    m_tamara->runAction( actionTo);
    m_grossini->runAction( CCSequence::create(actionBy, actionByBack, NULL));
	//CCRepeatForever是一個無限迴圈動畫。它將指定的動畫進行無限迴圈播放。
    m_kathia->runAction( CCRepeatForever::create(actionUp));
}
//顯示副標題。
std::string ActionJump::subtitle()
{
    return "JumpTo / JumpBy";
}

//第八種動畫演示表現的是讓演員們按照貝塞爾曲線的路徑運動。
class ActionBezier : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionBezier::onEnter()
{
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//取得螢幕大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();

	//將三位演員按居中對齊進行站位
    centerSprites(3);

    // 建立第一個貝塞爾曲線
    ccBezierConfig bezier;
    bezier.controlPoint_1 = CCPointMake(0, s.height/2);
    bezier.controlPoint_2 = CCPointMake(300, -s.height/2);
    bezier.endPosition = CCPointMake(300,100);
	//建立一個貝塞爾曲線動畫,這個CCBezierBy的意思是當前位置為曲線起點。曲線的其它點是相對於它的位置。
    CCActionInterval*  bezierForward = CCBezierBy::create(3, bezier);
	//建立上面動畫的反向播放動畫。
    CCActionInterval*  bezierBack = bezierForward->reverse();    
	//建立一個無限迴圈動畫序列,這個動畫序列由上面兩個動畫組成。    CCAction*  rep = CCRepeatForever::create((CCActionInterval*)CCSequence::create( bezierForward, bezierBack, NULL));


    // 建立第二個貝塞爾曲線
	// 設定一下女一號的當前位置。
    m_tamara->setPosition(CCPointMake(80,160));
    ccBezierConfig bezier2;
    bezier2.controlPoint_1 = CCPointMake(100, s.height/2);
    bezier2.controlPoint_2 = CCPointMake(200, -s.height/2);
    bezier2.endPosition = CCPointMake(240,160);
	//建立一個貝塞爾曲線動畫,這個CCBezierTo的意思是演員當前位置為曲線起點。曲線的其它點是螢幕的絕對位置。
    CCActionInterval*  bezierTo1 = CCBezierTo::create(2, bezier2);    

    //設定一下女二號的當前位置。建立相同的動畫。
    m_kathia->setPosition(CCPointMake(400,160));
	//如果剛才的ActionRotate 您理解的透徹,那這裡其實也可以改成:CCActionInterval*  bezierTo2 = (CCActionInterval*)(bezierTo1->copy()->autorelease());

    CCActionInterval*  bezierTo2 = CCBezierTo::create(2, bezier2);
	//三位演員開始動畫演示。
    m_grossini->runAction( rep);
    m_tamara->runAction(bezierTo1);
    m_kathia->runAction(bezierTo2);

}
//顯示副標題。
std::string ActionBezier::subtitle()
{
    return "BezierBy / BezierTo";
}

//第九種動畫演示表現的是演員們玩“我閃我閃亂你眼”
class ActionBlink : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionBlink::onEnter()
{
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//將二位女演員按居中對齊進行站位
    centerSprites(2);
	//這個CCBlink的create簡單,就是指定幾秒內共閃動幾次。
    CCActionInterval*  action1 = CCBlink::create(2, 10);
    CCActionInterval*  action2 = CCBlink::create(2, 5);
	//兩位演員開始表演“閃閃惹人愛”
    m_tamara->runAction( action1);
    m_kathia->runAction(action2);
}
//顯示副標題。
std::string  ActionBlink::subtitle()
{
    return "Blink";
}


//第十種動畫演示表現的是演員們淡入淡出
class ActionFade : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionFade::onEnter()
{
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//將二位女演員按居中對齊進行站位
    centerSprites(2);
	//設定女一號的透明度為0
    m_tamara->setOpacity( 0 );
	//CCFadeIn是一個淡入動畫,引數為秒數。代表需要多久顯示。
    CCActionInterval*  action1 = CCFadeIn::create(1.0f);
	//淡入的反向播放,其時是從演算法上實現了淡出。
    CCActionInterval*  action1Back = action1->reverse();
	//CCFadeOut是一個淡出動畫。引數為秒數。代表需要多久消融。
    CCActionInterval*  action2 = CCFadeOut::create(1.0f);
	//淡入的反向播放,其時是從演算法上實現了淡入。
    CCActionInterval*  action2Back = action2->reverse();
	//兩位女演員各自演員一個動畫序列。
    m_tamara->runAction( CCSequence::create( action1, action1Back, NULL));
    m_kathia->runAction( CCSequence::create( action2, action2Back, NULL));
}
//顯示副標題。
std::string  ActionFade::subtitle()
{
    return "FadeIn / FadeOut";
}

//第十一種動畫演示表現的是演員們如何進行色彩漸變。
class ActionTint : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionTint::onEnter()
{
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//將二位女演員按居中對齊進行站位
    centerSprites(2);
	//建立三個變色動畫,第一個是2秒時間變化到指定的色值。第二個是2秒時間從當前色彩狀態變化多少色值,第三個是第二個動畫的反向動畫。
    CCActionInterval*  action1 = CCTintTo::create(2, 255, 0, 255);
    CCActionInterval*  action2 = CCTintBy::create(2, -127, -255, -127);
    CCActionInterval*  action2Back = action2->reverse();
	//女一號執行動畫1。
    m_tamara->runAction( action1);
	//女二號執行一個動畫序列,這個動畫序列先執行動畫2,然後執行動畫3。
    m_kathia->runAction( CCSequence::create( action2, action2Back, NULL));
}

std::string  ActionTint::subtitle()
{
    return "TintTo / TintBy";
}


//第十二種動畫演示表現的是演員的逐幀動作動畫。
class ActionAnimate : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual void onExit();
    virtual std::string title();
    virtual std::string subtitle();
};
void ActionAnimate::onEnter()
{
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//將三位演員按居中對齊進行站位
    centerSprites(3);
	//建立一個序列幀動畫。
    CCAnimation* animation = CCAnimation::create();
	//載入15張圖片做為每幀顯示的精靈圖片。
    for( int i=1;i<15;i++)
    {
        char szName[100] = {0};
        sprintf(szName, "Images/grossini_dance_%02d.png", i);
        animation->addSpriteFrameWithFileName(szName);
    }
    //設定幀間隔時間。
    animation->setDelayPerUnit(2.8f / 14.0f);
	//設定動畫結束後保持初始幀資料不進行釋放。
    animation->setRestoreOriginalFrame(true);
	//建立序列幀動畫。
    CCAnimate* action = CCAnimate::create(animation);
	//男一號動行一個動畫序列,這個動畫序列先播放一遍序列幀動畫,然後再反向播放一遍序列幀動畫。
    m_grossini->runAction(CCSequence::create(action, action->reverse(), NULL));
    
    //下面演示了通過一個plist檔案來播放一個序列幀動畫。
	//先取得序列幀動畫管理器。
    CCAnimationCache *cache = CCAnimationCache::sharedAnimationCache();
	//載入一個plist檔案
    cache->addAnimationsWithFile("animations/animations-2.plist");
	//取得plist檔案中的對應序列幀動畫資訊
    CCAnimation *animation2 = cache->animationByName("dance_1");
	//以此資訊建立一個序列幀動畫。
    CCAnimate* action2 = CCAnimate::create(animation2);
	//女一號執行一個動畫序列,這個動畫序列先播放一遍序列幀動畫,然後再反向播放一遍序列幀動畫。
    m_tamara->runAction(CCSequence::create(action2, action2->reverse(), NULL));

	//產生一個plist檔案中的對應序列幀動畫資訊的拷貝
    CCAnimation *animation3 = (CCAnimation *)animation2->copy()->autorelease();
	//設定動畫資訊中的動畫迴圈次數
    animation3->setLoops(4);
	//以此資訊建立一個序列幀動畫。
    CCAnimate* action3 = CCAnimate::create(animation3);
	//女二號執行此動畫。
    m_kathia->runAction(action3);
}

void ActionAnimate::onExit()
{
    ActionsDemo::onExit();
    //TODO:[[NSNotificationCenter defaultCenter] removeObserver:observer_];
}

std::string ActionAnimate::title()
{
    return "Animation";
}

std::string ActionAnimate::subtitle()
{
    return "Center: Manual animation. Border: using file format animation";
}

//第十三種動畫演示的是多種動畫如何組成動畫序列。
class ActionSequence : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};

void ActionSequence::onEnter()
{
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//只需要男一號上場
    alignSpritesLeft(1);
	//建立一個動畫序列,先執行一個移動動畫,再執行一個旋轉動畫。
    CCFiniteTimeAction*  action = CCSequence::create(
        CCMoveBy::create( 2, CCPointMake(240,0)),
        CCRotateBy::create( 2,  540),
        NULL);
	//男一號演示此動畫。
    m_grossini->runAction(action);
}

std::string ActionSequence::subtitle()
{
    return "Sequence: Move + Rotate";
}

//第十四種動畫演示表現的是如何使多種動畫在組成動畫序列中能夠進行響應控制。
class ActionSequence2 : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();

    void callback1();
    void callback2(CCNode* sender);
    void callback3(CCNode* sender, void* data);
};
void ActionSequence2::onEnter()
{
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//只需要男一號上場
    alignSpritesLeft(1);
	//男一號設定不顯示
    m_grossini->setVisible(false);
	//建立一個序列動畫。這個序列動畫包含了一些動畫和回撥函式, CCCallFunc為不帶引數的回撥函式,CCCallFuncN為以演示當前動畫的演員為引數的回撥函式,CCCallFuncND為以演示當前動畫的演員和一個使用者輸入值為引數的回撥函式。
    CCFiniteTimeAction*  action = CCSequence::create(
        CCPlace::create(CCPointMake(200,200)),
        CCShow::create(),
        CCMoveBy::create(1, CCPointMake(100,0)),
        CCCallFunc::create(this, callfunc_selector(ActionSequence2::callback1)),
        CCCallFuncN::create(this, callfuncN_selector(ActionSequence2::callback2)),
        CCCallFuncND::create(this, callfuncND_selector(ActionSequence2::callback3), (void*)0xbebabeba),
        NULL);
	//男一號執行此動畫序列。
    m_grossini->runAction(action);
}
//不帶引數的回撥函式
void ActionSequence2::callback1()
{
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    CCLabelTTF *label = CCLabelTTF::create("callback 1 called", "Marker Felt", 16);
    label->setPosition(CCPointMake( s.width/4*1,s.height/2));

    addChild(label);
}
//以演示當前動畫的演員為引數的回撥函式
void ActionSequence2::callback2(CCNode* sender)
{
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    CCLabelTTF *label = CCLabelTTF::create("callback 2 called", "Marker Felt", 16);
    label->setPosition(CCPointMake( s.width/4*2,s.height/2));

    addChild(label);
}
//以演示當前動畫的演員和一個使用者輸入值為引數的回撥函式
void ActionSequence2::callback3(CCNode* sender, void* data)
{
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    CCLabelTTF *label = CCLabelTTF::create("callback 3 called", "Marker Felt", 16);
    label->setPosition(CCPointMake( s.width/4*3,s.height/2));

    addChild(label);
}

std::string ActionSequence2::subtitle()
{
    return "Sequence of InstantActions";
}

//第十五種動畫演示表現的是幾種動畫的並行,即如何同時進行多種動畫。
class ActionSpawn : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionSpawn::onEnter()
{
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//只需要男一號上場
    alignSpritesLeft(1);
	//建立一個動畫組合,使用方法與動畫序列類似了,這裡同時播放了跳躍和旋轉的動畫。
    CCAction*  action = CCSpawn::create(
        CCJumpBy::create(2, CCPointMake(300,0), 50, 4),
        CCRotateBy::create( 2,  720),
        NULL);
	//讓男一行執行此動畫組合。
    m_grossini->runAction(action);
}

std::string ActionSpawn::subtitle()
{
    return "Spawn: Jump + Rotate";
}

//第十六種動畫演示表現的是動畫的倒退重播,就像你看DVD按著後退鍵。
class ActionReverse : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionReverse::onEnter()
{
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//只需要男一號上場
    alignSpritesLeft(1);
	//建立一個跳躍動畫。
    CCActionInterval*  jump = CCJumpBy::create(2, CCPointMake(300,0), 50, 4);
	//建立一個動畫序列,先執行上面的跳躍動畫,再運其反向動畫。
    CCFiniteTimeAction*  action = CCSequence::create( jump, jump->reverse(), NULL);
	//男一號執行動畫。
    m_grossini->runAction(action);
}

std::string ActionReverse::subtitle()
{
    return "Reverse an action";
}

//第十七種動畫演示表現的是動畫的暫停與繼續播放。
class ActionDelayTime : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionDelayTime::onEnter()
{
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//只需要男一號上場
    alignSpritesLeft(1);
	//建立一個移動動畫。
    CCActionInterval*  move = CCMoveBy::create(1, CCPointMake(150,0));
	//建立一個動畫序列,先播放移動動畫,再暫停2秒,然後再播放移動動畫。
    CCFiniteTimeAction*  action = CCSequence::create( move, CCDelayTime::create(2), move, NULL);
	//男一行執行此動畫序列。
    m_grossini->runAction(action);
}

std::string ActionDelayTime::subtitle()
{
    return "DelayTime: m + delay + m";
}


//第十八種動畫演示表現的是動畫的重複播放。
class ActionRepeat : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionRepeat::onEnter()
{	//動畫演示的初始化
    ActionsDemo::onEnter();
	//兩位演員上場
    alignSpritesLeft(2);
	//建立一個移動動畫。
    CCActionInterval*  a1 = CCMoveBy::create(1, CCPointMake(150,0));
	//建立一個迴圈3次的序列動畫。序列動畫先設定精靈位置在60,60,然後播放上面的移動動畫。
    CCActionInterval*  action1 = CCRepeat::create(
        CCSequence::create( CCPlace::create(CCPointMake(60,60)), a1, NULL) , 
        3); 
	//建立一個無限迴圈動畫。這個無限迴圈的動畫是一個動畫序列,先播放第一個移動動畫,再播放其反向動畫。
    CCAction*  action2 = CCRepeatForever::create(
        (CCActionInterval*)(CCSequence::create((CCActionInterval*)(a1->copy()->autorelease()), a1->reverse(), NULL))
        );
	//女二號播放迴圈3次的序列動畫
    m_kathia->runAction(action1);
	//女一號播放無限迴圈動畫。
    m_tamara->runAction(action2);
}

std::string ActionRepeat::subtitle()
{
    return "Repeat / RepeatForever actions";
}

//第十九種動畫演示表現的是動畫的無限迴圈旋轉。
class ActionRepeatForever : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();

    void repeatForever(CCNode* pTarget);
};
void ActionRepeatForever::onEnter()
{	//動畫演示的初始化
    ActionsDemo::onEnter();
	//只需要男一號上場
    centerSprites(1);
	//建立一個動畫序列,先暫停1秒,然後呼叫
    CCFiniteTimeAction*  action = CCSequence::create(
        CCDelayTime::create(1),
        CCCallFuncN::create( this, callfuncN_selector(ActionRepeatForever::repeatForever) ), 
        NULL);
	//男一號執行此動畫。
    m_grossini->runAction(action);
}
//回撥函式。
void ActionRepeatForever::repeatForever(CCNode* pSender)
{
	//建立一個無限迴圈的旋轉動畫。
    CCRepeatForever *repeat = CCRepeatForever::create( CCRotateBy::create(1.0f, 360) );
	//讓男一號執行此無限迴圈動畫。
    pSender->runAction(repeat);
}

std::string ActionRepeatForever::subtitle()
{
    return "CallFuncN + RepeatForever";
}


//第二十種動畫演示表現的是動畫的無限迴圈旋轉到某個角度。
class ActionRotateToRepeat : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionRotateToRepeat::onEnter()
{	//動畫演示的初始化
    ActionsDemo::onEnter();
	//需要兩位演員
    centerSprites(2);
	//建立一個1秒內旋轉到90度的動畫
    CCActionInterval*  act1 = CCRotateTo::create(1, 90);
	//建立一個1秒內旋轉到0度的動畫
	CCActionInterval*  act2 = CCRotateTo::create(1, 0);
	//建立一個動畫序列,先執行動動畫1,再執行動畫2
    CCActionInterval*  seq = (CCActionInterval*)(CCSequence::create(act1, act2, NULL));
	//建立一個無限迴圈播放動畫序列的動畫。
	CCAction*  rep1 = CCRepeatForever::create(seq);
	//建立一個迴圈10次播放動畫序列的動畫。
    CCActionInterval*  rep2 = CCRepeat::create((CCFiniteTimeAction*)(seq->copy()->autorelease()), 10);
	//兩位演員分別播放相應的迴圈動畫。
    m_tamara->runAction(rep1);
    m_kathia->runAction(rep2);
}

std::string ActionRotateToRepeat ::subtitle()
{
    return "Repeat/RepeatForever + RotateTo";
}

//第二十一種動畫演示表現的是動畫的旋轉與反向旋轉。
class ActionRotateJerk : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionRotateJerk::onEnter()
{	//動畫演示的初始化
    ActionsDemo::onEnter();
	//需要兩位演員
    centerSprites(2);
	//建立一個動畫序列,先播放一個0.5秒旋轉到-20度的動畫,再播放一個0.5秒旋轉到20度的動畫。
    CCFiniteTimeAction*  seq = CCSequence::create(
        CCRotateTo::create(0.5f, -20),
        CCRotateTo::create(0.5f, 20),
        NULL);
	//建立一個迴圈播放10次上面的動畫序列的迴圈動畫。
	CCActionInterval*  rep1 = CCRepeat::create(seq, 10);
	//建立一個無限迴圈播放上面的動畫序列的迴圈動畫。
    CCAction*  rep2 = CCRepeatForever::create( (CCActionInterval*)(seq->copy()->autorelease()) );
	//兩位演員分別播放各自的迴圈動畫。
    m_tamara->runAction(rep1);
    m_kathia->runAction(rep2);
}

std::string ActionRotateJerk::subtitle()
{
    return "RepeatForever / Repeat + Rotate";
}

//第二十二種動畫演示表現的是動畫過程中的函式響應。
class ActionCallFunc : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();

    void callback1();
    void callback2(CCNode* pTarget);
    void callback3(CCNode* pTarget, void* data);
};
void ActionCallFunc::onEnter()
{	//動畫演示的初始化
    ActionsDemo::onEnter();
	//需要三位演員
    centerSprites(3);
	//建立一個動畫序列,先播放一個2秒橫向移動200的動畫,然後呼叫一個回撥函式。
    CCFiniteTimeAction*  action = CCSequence::create(
        CCMoveBy::create(2, CCPointMake(200,0)),
        CCCallFunc::create(this, callfunc_selector(ActionCallFunc::callback1)), 
        NULL);
	//建立一個動畫序列,先播放一個2秒放大2倍的動畫,再播放一個2秒的淡出動畫,之後呼叫一個回撥函式。
    CCFiniteTimeAction*  action2 = CCSequence::create(
        CCScaleBy::create(2 ,  2),
        CCFadeOut::create(2),
        CCCallFuncN::create(this, callfuncN_selector(ActionSequence2::callback2)), 
        NULL);
	//建立一個動畫序列,先播放一個3秒內旋轉360度的動畫,然後是一個2秒內淡出的動畫,之後呼叫一個回撥函式。
    CCFiniteTimeAction*  action3 = CCSequence::create(
        CCRotateBy::create(3 , 360),
        CCFadeOut::create(2),
        CCCallFuncND::create(this, callfuncND_selector(ActionSequence2::callback3), (void*)0xbebabeba), 
        NULL);
	//三位演員分別演示相應的動畫。
    m_grossini->runAction(action);
    m_tamara->runAction(action2);
    m_kathia->runAction(action3);
}

//第一個回撥函式。
void ActionCallFunc::callback1()
{
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    CCLabelTTF *label = CCLabelTTF::create("callback 1 called", "Marker Felt", 16);
    label->setPosition(CCPointMake( s.width/4*1,s.height/2));

    addChild(label);
}
//第二個回撥函式。
void ActionCallFunc::callback2(CCNode* pSender)
{
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    CCLabelTTF *label = CCLabelTTF::create("callback 2 called", "Marker Felt", 16);
    label->setPosition(CCPointMake( s.width/4*2,s.height/2));

    addChild(label);
}
//第三個回撥函式。
void ActionCallFunc::callback3(CCNode* pTarget, void* data)
{
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    CCLabelTTF *label = CCLabelTTF::create("callback 3 called", "Marker Felt", 16);
    label->setPosition(CCPointMake( s.width/4*3,s.height/2));
    addChild(label);
}

std::string ActionCallFunc::subtitle()
{
    return "Callbacks: CallFunc and friends";
}

//第二十二種動畫演示表現的是動畫過程中的帶引數的函式響應。
class ActionCallFuncND : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string title();
    virtual std::string subtitle();
    void removeFromParentAndCleanup(CCNode* pSender, void* data);
};
void ActionCallFuncND::onEnter()
{	//動畫演示的初始化
    ActionsDemo::onEnter();
	//只需要男演員上場。
    centerSprites(1);
	//建立一個動畫序列,首先播放一個2秒橫向移動200的動畫,然後呼叫一個回撥函式,可帶一個引數true。
    CCFiniteTimeAction* action = CCSequence::create(CCMoveBy::create(2.0f, ccp(200,0)),
        CCCallFuncND::create(this, callfuncND_selector(ActionCallFuncND::removeFromParentAndCleanup), (void*)true),
        NULL);
	//男演員演示動畫
    m_grossini->runAction(action);
}

std::string ActionCallFuncND::title()
{
    return "CallFuncND + auto remove";
}

std::string ActionCallFuncND::subtitle()
{
    return "CallFuncND + removeFromParentAndCleanup. Grossini dissapears in 2s";
}
//帶引數的回撥函式。data在這裡為true。
void ActionCallFuncND::removeFromParentAndCleanup(CCNode* pSender, void* data)
{
    bool bCleanUp = data != NULL;
    m_grossini->removeFromParentAndCleanup(bCleanUp);
}

//第二十三種動畫演示表現的是動畫的序列播放與反向序列播放。
class ActionReverseSequence : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionReverseSequence::onEnter()
{
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//只需要男演員上場。
    alignSpritesLeft(1);
	//建立一個移動動畫。
	CCActionInterval*  move1 = CCMoveBy::create(1, CCPointMake(250,0));
	//建立第二個移動動畫。
	CCActionInterval*  move2 = CCMoveBy::create(1, CCPointMake(0,50));
	//建立一個動畫序列,首先播放第一個移動動畫,再播放第二個移動動畫,最後播放第一個移動動畫的反向動畫。
    CCFiniteTimeAction*  seq = CCSequence::create( move1, move2, move1->reverse(), NULL);
	//建立一個動畫序列,先播放第一個動畫序列,然後播放這個動畫序列的反向動畫序列。
    CCFiniteTimeAction*  action = CCSequence::create( seq, seq->reverse(), NULL);
	//男演員演示這個動畫序列。
    m_grossini->runAction(action);
}

std::string ActionReverseSequence::subtitle()
{
    return "Reverse a sequence";
}

//第二十四種動畫演示表現的是動畫的序列播放與反向序列播放。
class ActionReverseSequence2 : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionReverseSequence2::onEnter()
{	//動畫演示的初始化
    ActionsDemo::onEnter();
	//需要兩位演員。
    alignSpritesLeft(2);
    //建立一個移動動畫。
	CCActionInterval*  move1 = CCMoveBy::create(1, CCPointMake(250,0));
	//建立第二個移動動畫。
	CCActionInterval*  move2 = CCMoveBy::create(1, CCPointMake(0,50));
	//建立兩個精靈顯示隱藏切換動畫。這個動畫會判斷精靈顯示狀態,如果顯示則切換為隱藏,如果隱藏則切換為顯示。
    CCToggleVisibility*  tog1 = new CCToggleVisibility();
    CCToggleVisibility*  tog2 = new CCToggleVisibility();
    tog1->autorelease();
	tog2->autorelease();
	//建立動畫序列,先播第一個移動動畫,然後隱藏,然後播第二個移動動畫,然後顯示,再播第一個移動動畫的反向動畫。
	CCFiniteTimeAction*  seq = CCSequence::create( move1, tog1, move2, tog2, move1->reverse(), NULL);
	//建立第二個動畫序列,先播放第一個動畫序列,再播放它的反向動畫序列。
    CCActionInterval*  action = CCRepeat::create((CCActionInterval*)(CCSequence::create( seq, seq->reverse(), NULL)), 3);



    //女二號播放第二個動畫序列.
    m_kathia->runAction(action);
	//建立一個移動動畫。
	CCActionInterval*  move_tamara = CCMoveBy::create(1, CCPointMake(100,0));
	//建立第二個移動動畫。
	CCActionInterval*  move_tamara2 = CCMoveBy::create(1, CCPointMake(50,0));
	//建立一個隱藏動畫,這個動畫的過程中精靈是處於隱藏狀態。
    CCActionInstant*  hide = new CCHide();
	hide->autorelease();
	//建立一個動畫序列,先執行第一個移動動畫,然後隱動畫,最後第二個移動動畫。
	CCFiniteTimeAction*  seq_tamara = CCSequence::create( move_tamara, hide, move_tamara2, NULL);
	//建立動畫序列的反向動畫序列。
	CCFiniteTimeAction*  seq_back = seq_tamara->reverse();
	//女一號執行一個動畫序列,這個動畫序列會先執行第一個動畫序列,然後再執行它的反向動畫序列。
    m_tamara->runAction( CCSequence::create( seq_tamara, seq_back, NULL));
}
std::string ActionReverseSequence2::subtitle()
{
    return "Reverse sequence 2";
}

//第二十五種動畫演示表現的是旋轉攝像機動畫,這時會用到攝像機球型運動演算法,攝像機會處在一個以目標物為球心的球體表面,其可以在球體表面上繞橫向和縱向軸旋轉。
class ActionOrbit : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionOrbit::onEnter()
{	//動畫演示的初始化
    ActionsDemo::onEnter();
	//需要三位演員。
    centerSprites(3);
	//建立第一個旋轉攝像機動畫。
	//建立的這個動畫為2秒內在半徑為1的球面上繞縱向軸轉180度。
	CCActionInterval*  orbit1 = CCOrbitCamera::create(2,1, 0, 0, 180, 0, 0);
	//建立第一個動畫序列,先執行攝像機動畫,再執行它的反向動畫。
    CCFiniteTimeAction*  action1 = CCSequence::create(
        orbit1,
        orbit1->reverse(),
        NULL);
	//建立第二個旋轉攝像機動畫以及動畫序列。
	//建立的這個動畫為2秒內在半徑為1的球面上,位置點在橫向軸旋轉-45度,然後動畫過程會沿以旋轉後的座標系在縱向軸轉180度。
    CCActionInterval*  orbit2 = CCOrbitCamera::create(2,1, 0, 0, 180, -45, 0);
    CCFiniteTimeAction*  action2 = CCSequence::create(
        orbit2,
        orbit2->reverse(),
        NULL);
	//建立第三個旋轉攝像機動畫及動畫序列。
	//建立的這個動畫為2秒內在半徑為1的球面上,位置點在橫向軸旋轉90度,然後動畫過程會沿以旋轉後的座標系在縱向軸轉180度,注意,這時候在世界座標系中看,其實是沿橫向軸轉180度~!
    CCActionInterval*  orbit3 = CCOrbitCamera::create(2,1, 0, 0, 180, 90, 0);
    CCFiniteTimeAction*  action3 = CCSequence::create(
        orbit3,
        orbit3->reverse(),
        NULL);

   	//三位演員分別播放相應的無限迴圈動畫。 m_kathia->runAction(CCRepeatForever::create((CCActionInterval*)action1));
    m_tamara->runAction(CCRepeatForever::create((CCActionInterval*)action2));
    m_grossini->runAction(CCRepeatForever::create((CCActionInterval*)action3));
	//建立一個移動動畫。
	CCActionInterval*  move = CCMoveBy::create(3, CCPointMake(100,-100));
	//建立這個移動動畫的反向動畫。
	CCActionInterval*  move_back = move->reverse();
	//將這兩個動畫放到一個動畫序列中。
	CCFiniteTimeAction*  seq = CCSequence::create(move, move_back, NULL);
	//建立一個無限迴圈動畫,播放這個動畫序列。
	CCAction*  rfe = CCRepeatForever::create((CCActionInterval*)seq);
	//三位演員要同時播放這個無限迴圈動畫。
    m_kathia->runAction(rfe);
    m_tamara->runAction((CCAction*)(rfe->copy()->autorelease()));
    m_grossini->runAction((CCAction*)(rfe->copy()->autorelease()));
}

std::string ActionOrbit::subtitle()
{
    return "OrbitCamera action";
}


//第二十六種動畫演示表現的是跟隨動畫。
class ActionFollow : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionFollow::onEnter()
{
	//動畫演示的初始化
    ActionsDemo::onEnter();
	//只需要一位演員上場
	centerSprites(1);
	//取得可視區域的大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
	//男一號設定位置。
	m_grossini->setPosition(CCPointMake(-200, s.height / 2));
	//建立一個移動動畫。
	CCActionInterval* move      = CCMoveBy::create(2, CCPointMake(s.width * 3, 0));
	//建立這個移動動畫的反向動畫。
	CCActionInterval* move_back = move->reverse();
	//建立一個動畫序列,先播放移動動畫,再播放其反向動畫。
	CCFiniteTimeAction* seq       = CCSequence::create(move, move_back, NULL);
	//建立一個無限迴圈動畫,播放這個動畫序列。
    CCAction* rep               = CCRepeatForever::create((CCActionInterval*)seq);
	//男一號演員這個無限迴圈動畫。
    m_grossini->runAction(rep);
	//當前層執行一個跟隨動畫,跟隨男一號,並設定其包圍區域。
    this->runAction(CCFollow::create(m_grossini, CCRectMake(0, 0, s.width * 2 - 100, s.height)));
}

std::string ActionFollow::subtitle()
{
    return "Follow action";
}

//第二十七種動畫演示表現的是控制目標動畫。
class ActionTargeted : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string title();
    virtual std::string subtitle();
};
void ActionTargeted::onEnter()
{	
	//動畫演示的初始化
	ActionsDemo::onEnter();
	//需要兩位演員上場
	centerSprites(2);
	//先建立一個跳躍動畫。
	CCJumpBy* jump1 = CCJumpBy::create(2,CCPointZero,100,3);
	//再建立一個相同的跳躍動畫。
	CCJumpBy* jump2 = (CCJumpBy*)jump1->copy()->autorelease();
	//建立一個旋轉動畫。
	CCRotateBy* rot1 =  CCRotateBy::create(1, 360);
	//再建立一個相同的旋轉動畫。
    CCRotateBy* rot2 = (CCRotateBy*)rot1->copy()->autorelease();
	//建立第一個控制目標動畫,讓女二號播放第二個跳躍動畫。
	CCTargetedAction *t1 = CCTargetedAction::create(m_kathia, jump2);
	//建立第二個控制目標動畫,讓女二號播放第二個旋轉動畫。
    CCTargetedAction *t2 = CCTargetedAction::create(m_kathia, rot2);

	//建立一個動畫序列,先播放一個第一個跳躍動畫,再播放第一個控制目標動畫,再播放第一個旋轉動畫,再播放第二個控制目標動畫。
	CCSequence* seq = (CCSequence*)CCSequence::create(jump1, t1, rot1, t2, NULL);
	//建立一個無限迴圈動畫,播放上面的動畫序列。
    CCRepeatForever *always = CCRepeatForever::create(seq);
	//女一號執行這個無限迴圈動畫。
    m_tamara->runAction(always);
}

std::string ActionTargeted::title()
{
    return "ActionTargeted";
}

std::string ActionTargeted::subtitle()
{
    return "Action that runs on another target. Useful for sequences";
}

//第二十八種動畫演示表現的是1305號動畫。
class Issue1305 : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual void onExit();
    void log(CCNode* pSender);
    void addSprite(float dt);
    virtual std::string title();
    virtual std::string subtitle();
private:
    CCSprite* m_pSpriteTmp;
};
void Issue1305::onEnter()
{	
	//動畫演示的初始化
	ActionsDemo::onEnter();
	//空無一人
    centerSprites(0);
	//建立一個精靈
    m_pSpriteTmp = CCSprite::create("Images/grossini.png");
	//讓精靈執行一個回撥函式列印一個日誌。注意:在這裡沒有讓精靈加入當前Layer,所以它不會真正的runAction,必須等它被掛在Layer下後才能被遍歷更新。
	
	m_pSpriteTmp->runAction(CCCallFuncN::create(this, callfuncN_selector(Issue1305::log)));
	//佔用精靈,故引用計數加一。
    m_pSpriteTmp->retain();
	//當前結點在2秒後呼叫回撥函式增加一個精靈。
    scheduleOnce(schedule_selector(Issue1305::addSprite), 2);
}
//精靈呼叫的回撥函式。
void Issue1305::log(CCNode* pSender)
{
    CCLog("This message SHALL ONLY appear when the sprite is added to the scene, NOT BEFORE");
}

void Issue1305::onExit()
{
    m_pSpriteTmp->release();
    ActionsDemo::onExit();
}

void Issue1305::addSprite(float dt)
{
	//在這裡設定精靈的位置並將其加入到當前的Layer下。
    m_pSpriteTmp->setPosition(ccp(250,250));
    addChild(m_pSpriteTmp);
}

上面這個動畫執行後,等2秒創建出精靈,然後動作管理器才能執行精靈執行的函式列印日誌,輸出到Output視窗。


std::string Issue1305::title()
{
    return "Issue 1305";
}

std::string Issue1305::subtitle()
{
    return "In two seconds you should see a message on the console. NOT BEFORE.";
}
//第二十九種動畫演示表現的是1305號動畫二。
class Issue1305_2 : public ActionsDemo
{
public:
    virtual void onEnter();
    void log1();
    void log2();
    void log3();
    void log4();
    virtual std::string title();
    virtual std::string subtitle();
};
void Issue1305_2::onEnter()
{
	//動畫演示的初始化
	ActionsDemo::onEnter();
	//不需要演員上場
    centerSprites(0);
	//建立一個精靈.載入一個圖。
	CCSprite *spr = CCSprite::create("Images/grossini.png");
	//設定位置
	spr->setPosition(ccp(200,200));
	//加入當前Layer。
    addChild(spr);
	//建立一個移動動畫。
    CCMoveBy* act1 = CCMoveBy::create(2 ,ccp(0, 100));
   	//建立一個回撥函式。
	CCCallFunc* act2 = CCCallFunc::create(this, callfunc_selector(Issue1305_2::log1)) ;
	//建立第二個移動動畫。
	CCMoveBy* act3 = CCMoveBy::create(2, ccp(0, -100));
	//建立第二個回撥函式。
	CCCallFunc* act4 = CCCallFunc::create(this, callfunc_selector(Issue1305_2::log2)) ;
	//建立第三個移動動畫。
	CCMoveBy* act5 = CCMoveBy::create(2, ccp(100, -100));
	//建立第三個回撥函式。
	CCCallFunc* act6 = CCCallFunc::create(this, callfunc_selector(Issue1305_2::log3)) ;
	//建立第四個移動動畫。
	CCMoveBy* act7 = CCMoveBy::create(2, ccp(-100, 0));
	//建立第四個回撥函式。
    CCCallFunc* act8 = CCCallFunc::create(this, callfunc_selector(Issue1305_2::log4)) ;
	//建立一個動畫序列,將前面的動畫都順序包含進來。
    CCFiniteTimeAction* actF = CCSequence::create(act1, act2, act3, act4, act5, act6, act7, act8, NULL);

   //通過動畫管理器來指定精靈播放動畫序列。    CCDirector::sharedDirector()->getActionManager()->addAction(actF ,spr, false);

}

void Issue1305_2::log1()
{
    CCLog("1st block");
}

void Issue1305_2::log2()
{
    CCLog("2nd block");
}

void Issue1305_2::log3()
{
    CCLog("3rd block");
}

void Issue1305_2::log4()
{
    CCLog("4th block");
}

std::string Issue1305_2::title()
{
    return "Issue 1305 #2";
}

std::string Issue1305_2::subtitle()
{
    return "See console. You should only see one message for each block";
}
//第三十種動畫演示表現的是1288號動畫。
class Issue1288 : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string title();
    virtual std::string subtitle();
};
void Issue1288::onEnter()
{
	//動畫演示的初始化
	ActionsDemo::onEnter();
	//不需要演員上場。
    centerSprites(0);
	//建立一個精靈,設定其位置並加入當前Layer。
    CCSprite *spr = CCSprite::create("Images/grossini.png");
    spr->setPosition(ccp(100, 100));
    addChild(spr);
	//建立兩個移動動畫。
    CCMoveBy* act1 = CCMoveBy::create(0.5, ccp(100, 0));
	CCMoveBy* act2 = (CCMoveBy*)act1->reverse();
	//將兩個動畫放入一個新建立的動畫序列。
	CCFiniteTimeAction* act3 = CCSequence::create(act1, act2, NULL);
	//建立一個迴圈2次播放動畫序列的動畫。
    CCRepeat* act4 = CCRepeat::create(act3, 2);
	//讓精靈播放這個迴圈2次播放動畫序列的動畫。
    spr->runAction(act4);
}

std::string Issue1288::title()
{
    return "Issue 1288";
}

std::string Issue1288::subtitle()
{
    return "Sprite should end at the position where it started.";
}
//第三十種動畫演示表現的是1288號動畫二。
class Issue1288_2 : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string title();
    virtual std::string subtitle();
};
void Issue1288_2::onEnter()
{
	//動畫演示的初始化
	ActionsDemo::onEnter();
	//不需要演員上場。
    centerSprites(0);
	//建立一個精靈,設定其位置並加入當前Layer。
    CCSprite *spr = CCSprite::create("Images/grossini.png");
    spr->setPosition(ccp(100, 100));
    addChild(spr);
	//建立一個移動動畫。
	CCMoveBy* act1 = CCMoveBy::create(0.5, ccp(100, 0));
	//建立一個迴圈播放1次上面的移動動畫,並讓精靈執行它。
    spr->runAction(CCRepeat::create(act1, 1));
}

std::string Issue1288_2::title()
{
    return "Issue 1288 #2";
}

std::string Issue1288_2::subtitle()
{
    return "Sprite should move 100 pixels, and stay there";
}
//第三十一種動畫演示表現的是1327號動畫。
class Issue1327 : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
    virtual std::string title();
    void logSprRotation(CCNode* pSender);
};
void Issue1327::onEnter()
{
	//動畫演示的初始化
	ActionsDemo::onEnter();
	//不需要演員上場。
    centerSprites(0);
	//建立一個精靈,設定其位置並加入當前Layer。
    CCSprite *spr = CCSprite::create("Images/grossini.png");
    spr->setPos