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();
}
}
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)
};
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()來控制場景的切換。
其他實例也是大同小異的,語言組織得不好,不知道大家看懂了沒,有問題或者意見的隨便提,謝謝支持。