Orca原创,转贴请标明链接Orca的移动开发轨迹。
目前整个学习笔记的版本是cocos2d-x 2.1.0beta3。
从这篇开始分析TestCpp的源码。这里借鉴了红孩儿的游戏编程之路的讲解方法,对此致谢。有点撞车,不过以下还是全部由我自己分析的内容。好了,开始吧。
这里看看整个TestCpp的控制流程,也就是说从control开始。
先看Appdelegate.cpp里面与HelloCpp不同的地方
// 创建TestController对象。 CCLayer * pLayer = new TestController(); pLayer->autorelease(); // // 改成这样可以吗? // CCLayer *pLayer = TestController::create(); pScene->addChild(pLayer); pDirector->runWithScene(pScene);
CCLayer *CCLayer::create() { CCLayer *pRet = new CCLayer(); if (pRet && pRet->init()) { pRet->autorelease(); return pRet; } else { CC_SAFE_DELETE(pRet); return NULL; } }这里不再深入解释,总之,一般的情况下,layer的构造方式是使用init()方法,把所有的都写在里面。而接下来我们就可以看到,这个controller的构造方式并非如此,所以不能使用这种方式来进行处理。
言归正传,可见TestCpp里面就是新建了一个TestController的Layer,用这个layer来控制整个testcpp。
好了,这样我们就去看看TestController。
先看头文件TestController.h
#ifndef _CONTROLLER_H_ #define _CONTROLLER_H_ #include "cocos2d.h" USING_NS_CC; class TestController : public CCLayer { public: // 构造函数 TestController(); // 析构函数 ~TestController(); // 菜单的返回方法 void menuCallback(CCObject * pSender); // 关闭的返回方法 void closeCallback(CCObject * pSender); // 重写触摸开始的方法 virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent); // 重写触摸移动的方法 virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent); private: // 开始位置 CCPoint m_tBeginPos; // Menu层 CCMenu* m_pItemMenu; }; #endif
#include "controller.h" // tests资源管理 #include "testResource.h" // tests管理 #include "tests.h" // 定义每一行标题的高度 #define LINE_SPACE 40 // 光标位置 static CCPoint s_tCurPos = CCPointZero; /************************************************************************/ /* 创建每一个测试场景 */ /************************************************************************/ static TestScene* CreateTestScene(int nIdx) { // 释放所有缓存 CCDirector::sharedDirector()->purgeCachedData(); // 创建指向场景的指针。TestScene是在testbasic.h里面声明的 TestScene* pScene = NULL; // 根据参数不同创建不同的场景 switch (nIdx) { // 枚举常量TEST_XXX是在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; #if (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE) // bada don't support libcurl #if (CC_TARGET_PLATFORM != CC_PLATFORM_BADA) case TEST_CURL: pScene = new CurlTestScene(); 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: pScene = new ShaderTestScene(); break; case TEST_MUTITOUCH: pScene = new MutiTouchTestScene(); break; #if (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE) case TEST_CLIPPINGNODE: pScene = new ClippingNodeTestScene(); break; #endif default: break; } // 返回创建的场景 return pScene; } // 构造函数 TestController::TestController() : m_tBeginPos(CCPointZero) { // add close menu // 增加关闭menu的MenuItemImage CCMenuItemImage *pCloseItem = CCMenuItemImage::create(s_pPathClose, s_pPathClose, this, menu_selector(TestController::closeCallback) ); // 创建menu CCMenu* pMenu =CCMenu::create(pCloseItem, NULL); // 设置menu层的位置在左下角 pMenu->setPosition( CCPointZero ); // 设置按钮的位置在右上角。这里的VisibleRect是由包含在tests.h里面的testbasic.h里面的VisibleRect.h来进行声明的,表示的是各个角落 pCloseItem->setPosition(ccp( VisibleRect::right().x - 30, VisibleRect::top().y - 30)); // add menu items for tests // 创建测试菜单 m_pItemMenu = CCMenu::create(); // TESTS_COUNT是在testbasic.h里面声明的 for (int i = 0; i < TESTS_COUNT; ++i) { // #if (CC_TARGET_PLATFORM == CC_PLATFORM_MARMALADE) // CCLabelBMFont* label = CCLabelBMFont::create(g_aTestNames[i].c_str(), "fonts/arial16.fnt"); // #else // 创建label,g_aTestNames是在tests.h里面。c_str()是封装的用于转换String类为C风格字符串字面值的方法 CCLabelTTF* label = CCLabelTTF::create(g_aTestNames[i].c_str(), "Arial", 24); // #endif // 通过Label创建MenuItem CCMenuItemLabel* pMenuItem = CCMenuItemLabel::create(label, this, menu_selector(TestController::menuCallback)); // 在测试菜单中加入这个MenuItem m_pItemMenu->addChild(pMenuItem, i + 10000); // 设置这个MenuItem的位置 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); // 在本Layer中添加测试菜单 addChild(m_pItemMenu); // 设置本层为可触摸 setTouchEnabled(true); // 在本Layer中添加关闭menu addChild(pMenu, 1); } TestController::~TestController() { } void TestController::menuCallback(CCObject * pSender) { // get the userdata, it's the index of the menu item clicked // 获取用户所点击的MenuItem的指针 CCMenuItem* pMenuItem = (CCMenuItem *)(pSender); // 根据定义时的zOrder获取MenuItem的id int nIdx = pMenuItem->getZOrder() - 10000; // create the test scene and run it // 根据id创建对应的场景 TestScene* pScene = CreateTestScene(nIdx); // 如果创建没有问题 if (pScene) { // 运行TestScene各派生类重写的虚函数runThisTest() pScene->runThisTest(); // 释放场景 pScene->release(); } } void TestController::closeCallback(CCObject * pSender) { // 关闭director CCDirector::sharedDirector()->end(); #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) exit(0); #endif } void TestController::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent) { // 获得当前CCTouch对象的指针 CCSetIterator it = pTouches->begin(); // 类型转换 CCTouch* touch = (CCTouch*)(*it); // 设置初始位置为第一个CCTouch的位置 m_tBeginPos = touch->getLocation(); } void TestController::ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent) { // 获得当前CCTouch对象的指针 CCSetIterator it = pTouches->begin(); // 类型转换 CCTouch* touch = (CCTouch*)(*it); // 获得当前的位置 CCPoint touchLocation = touch->getLocation(); // 获得移动了多少 float nMoveY = touchLocation.y - m_tBeginPos.y; // 获取整个Menu的位置 CCPoint curPos = m_pItemMenu->getPosition(); // 根据Y轴的移动量设置Menu的下一个位置 CCPoint nextPos = ccp(curPos.x, curPos.y + nMoveY); // 如果下一个位置的Y坐标低于最低值,则移动到最上面。 if (nextPos.y < 0.0f) { m_pItemMenu->setPosition(CCPointZero); return; } // 如果下一个位置的Y坐标高于最高值,则移动到最下面。 if (nextPos.y > ((TESTS_COUNT + 1)* LINE_SPACE - VisibleRect::getVisibleRect().size.height)) { m_pItemMenu->setPosition(ccp(0, ((TESTS_COUNT + 1)* LINE_SPACE - VisibleRect::getVisibleRect().size.height))); return; } // 不是以上两种情况则移动到下一个位置 m_pItemMenu->setPosition(nextPos); // 用于计算的初始位置移动到当前位置 m_tBeginPos = touchLocation; // 光标位置移动到下一个位置 s_tCurPos = nextPos; }
看完以后可以回答一下我们刚才的疑问。因为这里直接使用构造函数创建,而不是在init()里面构建的,所以无法使用create,而是必须new以后再autorelease()。
testResource.h里面全部都是资源的名字,没什么可说的。tests.h里面则是包含所有的头文件以及全局用的枚举值,也没什么好说的。
然后VisibleRect.h和VisibleRect.cpp主要是用来计算屏幕各参考点的位置的,基本没什么好说的。
接下来我们看一下在所有的测试例子中都引用了的testBasic.h及其源文件testBasic.cpp。
首先是testBasic.h:
#ifndef _TEST_BASIC_H_ #define _TEST_BASIC_H_ #include "cocos2d.h" #include "VisibleRect.h" USING_NS_CC; using namespace std; /************************************************************************/ /* TestScene类,所有的Test例子的场景都由这个类派生 */ /************************************************************************/ class TestScene : public CCScene { public: // 构造函数 TestScene(bool bPortrait = false); // 重写进入scene时的onEnter() virtual void onEnter(); // 纯虚函数runThisTest,说明本类不会被实例化。 virtual void runThisTest() = 0; // The CallBack for back to the main menu scene // 返回主菜单的CallBack函数 virtual void MainMenuCallback(CCObject* pSender); }; // 定义了一个指向无参数,返回值为CCLayer的函数指针NEWTESTFUNC typedef CCLayer* (*NEWTESTFUNC)(); // 定义了这样一个创建方法的宏 #define TESTLAYER_CREATE_FUNC(className) \ static CCLayer* create##className() \ { return new className(); } // 定义了创建宏 #define CF(className) create##className #endif
#include "testBasic.h" #include "controller.h" TestScene::TestScene(bool bPortrait) { // 直接调用CCScene基类的init方法 CCScene::init(); } void TestScene::onEnter() { // 先调用基类的onEnter方法 CCScene::onEnter(); //add the menu item for back to main menu //#if (CC_TARGET_PLATFORM == CC_PLATFORM_MARMALADE) // CCLabelBMFont* label = CCLabelBMFont::create("MainMenu", "fonts/arial16.fnt"); //#else // 创建返回主页面的label文字 CCLabelTTF* label = CCLabelTTF::create("MainMenu", "Arial", 20); //#endif // 以“MainMenu”文字作为MenuItem,它的callback参数就是MaiMenuCallback CCMenuItemLabel* pMenuItem = CCMenuItemLabel::create(label, this, menu_selector(TestScene::MainMenuCallback)); // 创建MainMenu这个Item的Menu CCMenu* pMenu =CCMenu::create(pMenuItem, NULL); // MenuItem放到左下角 pMenu->setPosition( CCPointZero ); // MenuItem放到右中间的位置 pMenuItem->setPosition( ccp( VisibleRect::right().x - 50, VisibleRect::bottom().y + 25) ); // 把这个menu加入本scene addChild(pMenu, 1); } void TestScene::MainMenuCallback(CCObject* pSender) { // 创建一个scene CCScene* pScene = CCScene::create(); // scene中创建testController,并加入自动回收 CCLayer* pLayer = new TestController(); pLayer->autorelease(); // pLayer加入scene pScene->addChild(pLayer); // 替换掉当前Scene CCDirector::sharedDirector()->replaceScene(pScene); }
整个控制代码基本就看完了。看完这些代码,其实已经可以完成一个完整的SceneManager了。如果有看我博客的朋友,可以自己试一下,很简单的。
下一篇开始正式进入各个测试类的内容当中