Cocos2d-x TestApp分析

        Cocos2d-x引擎自帶的解決方案中的TestApp絕對是新手學習的好材料,下面就來分析一下TestApp的結構。我的引擎版本是cocos2d-x-2.2。



        

打開解決方案cocos2d-win32.vc2010.sln,查看TestApp-》Classes:


testResource:存放資源路徑的頭文件

tests:添加頭文件和主界面菜單的文字

VisibleRect:取得屏幕的各個邊界點


1、main:win32程序的入口

    // 創建一個應用實例
    AppDelegate app;	
    CCEGLView* eglView = CCEGLView::sharedOpenGLView();
    eglView->setViewName("TestCpp");
    eglView->setFrameSize(960, 640);
    return CCApplication::sharedApplication()->run();	// 運行程序

2、AppDelegate:

bool AppDelegate::applicationDidFinishLaunching()	// 入口
{
	// As an example, load config file
	// XXX: This should be loaded before the Director is initialized,
	// XXX: but at this point, the director is already initialized
	CCConfiguration::sharedConfiguration()->loadConfigFile("configs/config-example.plist");

    // initialize director
    CCDirector *pDirector = CCDirector::sharedDirector();
    pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());

    CCSize screenSize = CCEGLView::sharedOpenGLView()->getFrameSize();

    CCSize designSize = CCSizeMake(480, 320);

    CCFileUtils* pFileUtils = CCFileUtils::sharedFileUtils();
    std::vector<std::string> searchPaths;
    
	if (screenSize.height > 320)
    {
		// 如果屏幕高度大於320,則設置資源搜索路徑
        CCSize resourceSize = CCSizeMake(960, 640);
        searchPaths.push_back("hd");
		searchPaths.push_back("hd/scenetest");
        pDirector->setContentScaleFactor(resourceSize.height/designSize.height);
    }
	else
	{
		searchPaths.push_back("scenetest");
	}
	pFileUtils->setSearchPaths(searchPaths);

 #if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
    CCEGLView::sharedOpenGLView()->setDesignResolutionSize(designSize.width, designSize.height, kResolutionShowAll);
#else
	CCEGLView::sharedOpenGLView()->setDesignResolutionSize(designSize.width, designSize.height, kResolutionNoBorder);
#endif

	// 將佈景添加到場景中並執行
    CCScene * pScene = CCScene::create();
    CCLayer * pLayer = new TestController();
    pLayer->autorelease();

    pScene->addChild(pLayer);
    pDirector->runWithScene(pScene);

    return true;
}


3、TestController是controller的類,繼承CCLayer,也就是我們運行程序時的主界面,先看構造函數:

TestController::TestController()
: m_tBeginPos(CCPointZero)
{
    // 添加右上角的關閉菜單
    CCMenuItemImage *pCloseItem = CCMenuItemImage::create(s_pPathClose, s_pPathClose, this, menu_selector(TestController::closeCallback) );
    CCMenu* pMenu =CCMenu::create(pCloseItem, NULL);

    pMenu->setPosition( CCPointZero );
    pCloseItem->setPosition(ccp( VisibleRect::right().x - 30, VisibleRect::top().y - 30));

    // 循環tests.h頭文件的g_aTestNames名字數組,添加文字菜單
    m_pItemMenu = CCMenu::create();
    for (int i = 0; i < TESTS_COUNT; ++i)
    {
        CCLabelTTF* label = CCLabelTTF::create(g_aTestNames[i].c_str(), "Arial", 24);       
        CCMenuItemLabel* pMenuItem = CCMenuItemLabel::create(label, this, menu_selector(TestController::menuCallback));

        m_pItemMenu->addChild(pMenuItem, i + 10000);	// 這裏設置點擊的標記,讓程序知道我點擊的究竟是哪個文字菜單項
        pMenuItem->setPosition( ccp( VisibleRect::center().x, (VisibleRect::top().y - (i + 1) * LINE_SPACE) ));
    }

    m_pItemMenu->setContentSize(CCSizeMake(VisibleRect::getVisibleRect().size.width, (TESTS_COUNT + 1) * (LINE_SPACE)));
    m_pItemMenu->setPosition(s_tCurPos);
    addChild(m_pItemMenu);

    setTouchEnabled(true);

    addChild(pMenu, 1);

}

運行了程序後我們知道:每點擊一個文字菜單項都會跳轉到不同的場景,下面來看看菜單回調函數menuCallback:

void TestController::menuCallback(CCObject * pSender)
{
    // 通過這兩句代碼來識別點擊的文字菜單項
    CCMenuItem* pMenuItem = (CCMenuItem *)(pSender);
    int nIdx = pMenuItem->getZOrder() - 10000;

    // 新建一個場景並運行
    TestScene* pScene = CreateTestScene(nIdx);
    if (pScene)
    {
        pScene->runThisTest();
        pScene->release();
    }
}


我們調用CreateTestScene()函數,獲得一個創建好的場景,然後調用runThisTest()來切換場景,看看CreateTestScene()是何方神聖:

static TestScene* CreateTestScene(int nIdx)
{
    CCDirector::sharedDirector()->purgeCachedData();

    TestScene* pScene = NULL;

    switch (nIdx)
    {
	// 下面的這些類,存放在Classes下的那些文件夾中,比如ActionTestScene存放在Classes\ActionTest中,
	// ActionTest的頭文件已經在tests.h中導入了
    case TEST_ACTIONS:
        pScene = new ActionsTestScene(); break;
    case TEST_TRANSITIONS:
        pScene = new TransitionsTestScene(); break;
     case TEST_PROGRESS_ACTIONS:
         pScene = new ProgressActionsTestScene(); break;
    case TEST_EFFECTS:
        pScene = new EffectTestScene(); break;
    case TEST_CLICK_AND_MOVE:
        pScene = new ClickAndMoveTestScene(); break;
    case TEST_ROTATE_WORLD:
        pScene = new RotateWorldTestScene(); break;
    case TEST_PARTICLE:
        pScene = new ParticleTestScene(); break;
    case TEST_EASE_ACTIONS:
        pScene = new ActionsEaseTestScene(); break;
    case TEST_MOTION_STREAK:
        pScene = new MotionStreakTestScene(); break;
    case TEST_DRAW_PRIMITIVES:
        pScene = new DrawPrimitivesTestScene(); break;
    case TEST_COCOSNODE:
        pScene = new CocosNodeTestScene(); break;
    case TEST_TOUCHES:
        pScene = new PongScene(); break;
    case TEST_MENU:
        pScene = new MenuTestScene(); break;
    case TEST_ACTION_MANAGER:
        pScene = new ActionManagerTestScene(); break;
    case TEST_LAYER:
        pScene = new LayerTestScene(); break;
    case TEST_SCENE:
        pScene = new SceneTestScene(); break;
    case TEST_PARALLAX:
        pScene = new ParallaxTestScene(); break;
    case TEST_TILE_MAP:
        pScene = new TileMapTestScene(); break;
    case TEST_INTERVAL:
        pScene = new IntervalTestScene(); break;
    case TEST_LABEL:
        pScene = new AtlasTestScene(); break;
    case TEST_TEXT_INPUT:
        pScene = new TextInputTestScene(); break;
    case TEST_SPRITE:
        pScene = new SpriteTestScene(); break;
    case TEST_SCHEDULER:
        pScene = new SchedulerTestScene(); break;
    case TEST_RENDERTEXTURE:
        pScene = new RenderTextureScene(); break;
    case TEST_TEXTURE2D:
        pScene = new TextureTestScene(); break;
#if (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE)
    case TEST_CHIPMUNK:
        pScene = new ChipmunkAccelTouchTestScene(); break;
#endif
    case TEST_BOX2D:
        pScene = new Box2DTestScene(); break;
    case TEST_BOX2DBED:
        pScene = new Box2dTestBedScene(); break;
    case TEST_EFFECT_ADVANCE:
        pScene = new EffectAdvanceScene(); break;
    case TEST_ACCELEROMRTER:
        pScene = new AccelerometerTestScene(); break;
#if (CC_TARGET_PLATFORM != CC_PLATFORM_BADA)
    case TEST_KEYPAD:
        pScene = new KeypadTestScene(); break;
#endif
    case TEST_COCOSDENSHION:
        pScene = new CocosDenshionTestScene(); break;
    case TEST_PERFORMANCE:
        pScene = new PerformanceTestScene(); break;
    case TEST_ZWOPTEX:
        pScene = new ZwoptexTestScene(); break;
// bada don't support libcurl
#if (CC_TARGET_PLATFORM != CC_PLATFORM_BADA && CC_TARGET_PLATFORM != CC_PLATFORM_NACL && CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE && CC_TARGET_PLATFORM != CC_PLATFORM_EMSCRIPTEN)
    case TEST_CURL:
	#if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT) && (CC_TARGET_PLATFORM != CC_PLATFORM_WP8)
        pScene = new CurlTestScene(); break;
    #else
	    CCMessageBox("CurlTest not yet implemented.","Alert"); break;
    #endif
#endif
    case TEST_USERDEFAULT:
        pScene = new UserDefaultTestScene(); break;
    case TEST_BUGS:
        pScene = new BugsTestScene(); break;
    case TEST_FONTS:
        pScene = new FontTestScene(); break;
    case TEST_CURRENT_LANGUAGE:
        pScene = new CurrentLanguageTestScene(); break;
#if (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE)
    case TEST_TEXTURECACHE: pScene = new TextureCacheTestScene(); break;
#endif
    case TEST_EXTENSIONS:
        pScene = new ExtensionsTestScene();
        break;
    case TEST_SHADER:
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WP8)
       pScene = new ShaderTestScene();
#else
		CCMessageBox("ShaderTest not yet implemented.","Alert");
#endif          
    break;

    case TEST_MUTITOUCH:
        pScene = new MutiTouchTestScene();
        break;
#if (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE)
    case TEST_CLIPPINGNODE:
        pScene = new ClippingNodeTestScene();
        break;
#endif
    case TEST_FILEUTILS:
        pScene = new FileUtilsTestScene();
        break;
    case TEST_SPINE:
        pScene = new SpineTestScene();
        break;
    case TEST_TEXTUREPACKER_ENCRYPTION:
        pScene = new TextureAtlasEncryptionTestScene();
        break;
    case TEST_DATAVISTOR:
        pScene = new DataVisitorTestScene();
        break;
	case TEST_CONFIGURATION:
		pScene = new ConfigurationTestScene();
		break;
	default:
        break;
    }

    return pScene;
}

4、舉一個具體的例子,比如CreateTestScene(1),執行pScene = new ActionTestScene(),並返回,此時執行pScene->runThisTest()。去ActionTest.cpp中的runThisTest():

class ActionsTestScene : public TestScene
{
public:
    virtual void runThisTest();
};


5、可以發現,ActionTestScene是繼承TestScene的,而TestScene存放在testBasic.cpp中,繼續查看testBasic.cpp中的TestScene:

void TestScene::onEnter()
{
    CCScene::onEnter();

	// 添加返回主場景(controller)的文字菜單
    CCLabelTTF* label = CCLabelTTF::create("MainMenu", "Arial", 20);
    CCMenuItemLabel* pMenuItem = CCMenuItemLabel::create(label, this, menu_selector(TestScene::MainMenuCallback));

    CCMenu* pMenu =CCMenu::create(pMenuItem, NULL);

    pMenu->setPosition( CCPointZero );
    pMenuItem->setPosition( ccp( VisibleRect::right().x - 50, VisibleRect::bottom().y + 25) );

    addChild(pMenu, 1);
}

void TestScene::MainMenuCallback(CCObject* pSender)
{
	// 可以發現這裏的代碼跟AppDelegate啓動主場景的代碼是一樣的
    CCScene* pScene = CCScene::create();
    CCLayer* pLayer = new TestController();
    pLayer->autorelease();

    pScene->addChild(pLayer);
    CCDirector::sharedDirector()->replaceScene(pScene);
}

6、回到ActionTestScene中查看runThisTest():

void ActionsTestScene::runThisTest()
{
    sceneIdx = -1;
    addChild(nextAction());

    CCDirector::sharedDirector()->replaceScene(this);
}

nextAction()又是什麼,nextAction()、backAction()、restartAction()對應的是程序下面的三個按鈕:下一個、上一個、重啓:

static CCLayer* nextAction()
{
    sceneIdx++;
    sceneIdx = sceneIdx % MAX_LAYER;
    
    CCLayer* pLayer = (createFunctions[sceneIdx])();
    pLayer->init();
    pLayer->autorelease();
    
    return pLayer;
}

static CCLayer* backAction()
{
    sceneIdx--;
    int total = MAX_LAYER;
    if( sceneIdx < 0 )
        sceneIdx += total;
    
    CCLayer* pLayer = (createFunctions[sceneIdx])();
    pLayer->init();
    pLayer->autorelease();
    
    return pLayer;
}

static CCLayer* restartAction()
{
    CCLayer* pLayer = (createFunctions[sceneIdx])();
    pLayer->init();
    pLayer->autorelease();
    
    return pLayer;
}

佈景是怎麼創建的呢,查看createFunctions[]數組:

TESTLAYER_CREATE_FUNC(ActionManual);
TESTLAYER_CREATE_FUNC(ActionMove);
TESTLAYER_CREATE_FUNC(ActionRotate);
TESTLAYER_CREATE_FUNC(ActionScale);
TESTLAYER_CREATE_FUNC(ActionSkew);
TESTLAYER_CREATE_FUNC(ActionRotationalSkew);
TESTLAYER_CREATE_FUNC(ActionRotationalSkewVSStandardSkew);
TESTLAYER_CREATE_FUNC(ActionSkewRotateScale);
TESTLAYER_CREATE_FUNC(ActionJump);
TESTLAYER_CREATE_FUNC(ActionCardinalSpline);
TESTLAYER_CREATE_FUNC(ActionCatmullRom);
TESTLAYER_CREATE_FUNC(ActionBezier);
TESTLAYER_CREATE_FUNC(ActionBlink);
TESTLAYER_CREATE_FUNC(ActionFade);
TESTLAYER_CREATE_FUNC(ActionTint);
TESTLAYER_CREATE_FUNC(ActionAnimate);
TESTLAYER_CREATE_FUNC(ActionSequence);
TESTLAYER_CREATE_FUNC(ActionSequence2);
TESTLAYER_CREATE_FUNC(ActionSpawn);
TESTLAYER_CREATE_FUNC(ActionReverse);
TESTLAYER_CREATE_FUNC(ActionDelayTime);
TESTLAYER_CREATE_FUNC(ActionRepeat);
TESTLAYER_CREATE_FUNC(ActionRepeatForever);
TESTLAYER_CREATE_FUNC(ActionRotateToRepeat);
TESTLAYER_CREATE_FUNC(ActionRotateJerk);
TESTLAYER_CREATE_FUNC(ActionCallFunc);
TESTLAYER_CREATE_FUNC(ActionCallFuncND);
TESTLAYER_CREATE_FUNC(ActionReverseSequence);
TESTLAYER_CREATE_FUNC(ActionReverseSequence2);
TESTLAYER_CREATE_FUNC(ActionRemoveSelf);
TESTLAYER_CREATE_FUNC(ActionOrbit);
TESTLAYER_CREATE_FUNC(ActionFollow);
TESTLAYER_CREATE_FUNC(ActionTargeted);
TESTLAYER_CREATE_FUNC(ActionMoveStacked);
TESTLAYER_CREATE_FUNC(ActionMoveJumpStacked);
TESTLAYER_CREATE_FUNC(ActionMoveBezierStacked);
TESTLAYER_CREATE_FUNC(ActionCardinalSplineStacked);
TESTLAYER_CREATE_FUNC(ActionCatmullRomStacked);
TESTLAYER_CREATE_FUNC(PauseResumeActions);
TESTLAYER_CREATE_FUNC(Issue1305);
TESTLAYER_CREATE_FUNC(Issue1305_2);
TESTLAYER_CREATE_FUNC(Issue1288);
TESTLAYER_CREATE_FUNC(Issue1288_2);
TESTLAYER_CREATE_FUNC(Issue1327);
TESTLAYER_CREATE_FUNC(Issue1398);


static NEWTESTFUNC createFunctions[] = {
    CF(ActionManual),
    CF(ActionMove),
    CF(ActionRotate),
    CF(ActionScale),
    CF(ActionSkew),
    CF(ActionRotationalSkew),
    CF(ActionRotationalSkewVSStandardSkew),
    CF(ActionSkewRotateScale),
    CF(ActionJump),
    CF(ActionCardinalSpline),
    CF(ActionCatmullRom),
    CF(ActionBezier),
    CF(ActionBlink),
    CF(ActionFade),
    CF(ActionTint),
    CF(ActionAnimate),
    CF(ActionSequence),
    CF(ActionSequence2),
    CF(ActionRemoveSelf),
    CF(ActionSpawn),
    CF(ActionReverse),
    CF(ActionDelayTime),
    CF(ActionRepeat),
    CF(ActionRepeatForever),
    CF(ActionRotateToRepeat),
    CF(ActionRotateJerk),
    CF(ActionCallFunc),
    CF(ActionCallFuncND),
    CF(ActionReverseSequence),
    CF(ActionReverseSequence2),
    CF(ActionOrbit),
    CF(ActionFollow),
    CF(ActionTargeted),
    CF(ActionMoveStacked),
    CF(ActionMoveJumpStacked),
    CF(ActionMoveBezierStacked),
    CF(ActionCardinalSplineStacked),
    CF(ActionCatmullRomStacked),
    CF(PauseResumeActions),
    CF(Issue1305),
    CF(Issue1305_2),
    CF(Issue1288),
    CF(Issue1288_2),
    CF(Issue1327),
    CF(Issue1398)
};


7、NEWTESTFUNC是一個返回CCLayer* 的函數指針類型,TESTLAYER_CREATE_FUNC和CF都是宏,這些存放在testBasic.h中:

typedef CCLayer* (*NEWTESTFUNC)();
#define TESTLAYER_CREATE_FUNC(className) \
static CCLayer* create##className() \
{ return new className(); }

#define CF(className) create##className

8、回到第六步,假設打開第一個界面:

(createFunctions[0])()  -->  (CF(ActionManual))()  -->  createActionManual()

TESTLAYER_CREATE_FUNC(ActionManual)  --> createActionManual() -->  return new ActionManual()

綜上,這裏主要是將各個佈景的實例添加到createFunctions數組中,通過nextAction(),backAction(),restartAction()來控制場景的切換。


        其他實例也是大同小異的,語言組織得不好,不知道大家看懂了沒,有問題或者意見的隨便提,謝謝支持。










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