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()来控制场景的切换。
其他实例也是大同小异的,语言组织得不好,不知道大家看懂了没,有问题或者意见的随便提,谢谢支持。