(原创)cocos2d-x 3.0 示例代码分析2:TestController

星月最近有点忙,所以博客更新落下了~~~(小白:赶紧进入正题。。。)

上一篇文章中http://www.cnblogs.com/wodehao0808/p/4019587.html,有段代码:

// 创建图层
auto layer = new TestController(); 

在本章中看下这个layer是用来做啥的,哈哈哈~~~(小白:傻笑你妹~~)

-- TestController.h

// TestController是一个Layer,用这个layer来控制整个testcpp

#ifndef _CONTROLLER_H_
#define _CONTROLLER_H_

#include "cocos2d.h"

USING_NS_CC;

class TestController : public Layer
{
public:
    // 构造函数
    TestController();
    // 析构函数
    ~TestController();

    // 菜单按钮回调
    void menuCallback(Ref * sender);
    // 关闭按钮回调
    void closeCallback(Ref * sender);

    // 触摸:开始
    bool onTouchBegan(Touch* touches, Event  *event);
    // 触摸:移动
    void onTouchMoved(Touch* touches, Event  *event);

    // 鼠标:滚动
    void onMouseScroll(Event *event);
    // 函数实现了控制台,用于文本输入输出
    void addConsoleAutoTest();

private:
    Point _beginPos;  // 开始触摸点
    Menu* _itemMenu;  // 菜单按钮
};

#endif

上面是头文件,里面注释很清楚。3.0增加了一个:鼠标:滚动。功能,越来越强大了。。。

接下来看.cpp文件。。。

// TestController.h



// C++ includes
#include <map>
#include <functional>
#include <string>
#include <chrono>  // 日期时间相关的库,参考资料: http://www.2cto.com/kf/201404/290706.html 
#include <thread>  // 线程操作的类, 参考资料:http://www.cocoachina.com/cocos/20140523/8530.html
// test inclues
#include "AppDelegate.h"
#include "BaseTest.h"    // 基类,提供场景一些公共功能,详情请查看该类的说明文章。(小白:你出了吗?星月:还没...)
#include "controller.h"
#include "testResource.h"  // 资源配置
#include "tests.h"  // 头文件集合~~~

#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32) && (CC_TARGET_PLATFORM != CC_PLATFORM_WP8) && (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT)
#include <unistd.h>
#include <sys/socket.h>
#else
#include <io.h>
#endif
#include "cocostudio/CocoStudio.h"

// 定义数据结构:变量名,一个返回TestScene指针的函数
typedef struct _Controller{
    const char *test_name;
    std::function<TestScene*()> callback;
} Controller;

// Controller类型的数组变量
Controller g_aTestNames[] = {

    //
    // TESTS MUST BE ORDERED ALPHABETICALLY
    //     violators will be prosecuted
    //
    // 第一个参数是name,第二个参数是:返回生成的新的scene。的函数方法
    // 星月:对c++ 11 新特性不是很了解,上面是按照自己的理解去解释的,不一定正确,欢迎各位指出错误(小白:你个坑货~~~)
    { "Accelerometer", []() { return new AccelerometerTestScene(); } },  
    { "ActionManager", [](){return new ActionManagerTestScene(); } },
    { "Actions - Basic", [](){ return new ActionsTestScene(); } },
    { "Actions - Ease", [](){return new ActionsEaseTestScene();} },
    { "Actions - Progress", [](){return new ProgressActionsTestScene(); } },
    { "Audio - CocosDenshion", []() { return new CocosDenshionTestScene(); } },
    { "Box2d - Basic", []() { return new Box2DTestScene(); } },
    { "Box2d - TestBed", []() { return new Box2dTestBedScene(); } },
    { "Bugs", []() { return new BugsTestScene(); } },
    { "Chipmunk", []() { return new ChipmunkAccelTouchTestScene(); } },
    { "Click and Move", [](){return new ClickAndMoveTestScene(); } },
    { "Configuration", []() { return new ConfigurationTestScene(); } },
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WP8)
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT)
    { "Console", []() { return new ConsoleTestScene(); } },
#endif
#endif
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WP8)
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT)
#if (CC_TARGET_PLATFORM != CC_PLATFORM_EMSCRIPTEN)
#if (CC_TARGET_PLATFORM != CC_PLATFORM_NACL)
#if (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE)
#if (CC_TARGET_PLATFORM != CC_PLATFORM_BADA)
    { "Curl", []() { return new CurlTestScene(); } },
#endif
#endif
#endif
#endif
#endif
#endif
    { "Current Language", []() { return new CurrentLanguageTestScene(); } },
    { "EventDispatcher", []() { return new EventDispatcherTestScene(); } },
    { "Effects - Advanced", []() { return new EffectAdvanceScene(); } },
    { "Effects - Basic", [](){return new EffectTestScene();} },
    { "Extensions", []() { return new ExtensionsTestScene(); } },
    { "FileUtils", []() { return new FileUtilsTestScene(); } },
    { "Fonts", []() { return new FontTestScene(); } },
    { "Interval", [](){return new IntervalTestScene(); } },
    { "Keyboard", []() { return new KeyboardTestScene(); } },
    { "Keypad", []() { return new KeypadTestScene(); } },
    { "Node: Clipping", []() { return new ClippingNodeTestScene(); } },
    { "Node: Draw", [](){return new DrawPrimitivesTestScene();} },
    { "Node: Label - New API", [](){return new AtlasTestSceneNew(); } },
    { "Node: Label - Old API", [](){return new AtlasTestScene(); } },
    { "Node: Layer", [](){return new LayerTestScene();} },
    { "Node: Menu", [](){return new MenuTestScene();} },
    { "Node: MotionStreak", [](){return new MotionStreakTestScene();} },
    { "Node: Node", [](){return new CocosNodeTestScene();} },
    { "Node: Parallax", [](){return new ParallaxTestScene(); } },
    { "Node: Particles", [](){return new ParticleTestScene(); } },
    { "Node: Physics", []() { return new PhysicsTestScene(); } },
    { "Node: RenderTexture", [](){return new RenderTextureScene(); } },
    { "Node: Scene", [](){return new SceneTestScene();} },
    { "Node: Spine", []() { return new SpineTestScene(); } },
    { "Node: Sprite", [](){return new SpriteTestScene(); } },
    { "Node: TileMap", [](){return new TileMapTestScene(); } },
    { "Node: Text Input", [](){return new TextInputTestScene(); } },
    { "Mouse", []() { return new MouseTestScene(); } },
    { "MutiTouch", []() { return new MutiTouchTestScene(); } },
    { "Performance tests", []() { return new PerformanceTestScene(); } },
    { "Renderer", []() { return new NewRendererTestScene(); } },
    { "ReleasePool", [](){ return new ReleasePoolTestScene(); } },
    { "Rotate World", [](){return new RotateWorldTestScene(); } },
    { "Scheduler", [](){return new SchedulerTestScene(); } },
    { "Shader - Basic", []() { return new ShaderTestScene(); } },
    { "Shader - Sprite", []() { return new ShaderTestScene2(); } },
    { "Texture2D", [](){return new TextureTestScene(); } },
    { "TextureCache", []() { return new TextureCacheTestScene(); } },
    { "TexturePacker Encryption", []() { return new TextureAtlasEncryptionTestScene(); } },
    { "Touches", [](){return new PongScene();} },
    { "Transitions", [](){return new TransitionsTestScene();} },
    { "Unit Test", []() { return new UnitTestScene(); }},
    { "UserDefault", []() { return new UserDefaultTestScene(); } },
    { "Zwoptex", []() { return new ZwoptexTestScene(); } },
};

static int g_testCount = sizeof(g_aTestNames) / sizeof(g_aTestNames[0]);  // 获得菜单项数目
static Controller *currentController = nullptr;  // 定义一个静态指针,指向当前打开的场景
#define LINE_SPACE          40  // 菜单项之间的间距

static Point s_tCurPos = Point::ZERO;  // 定义一个静态位置变量,当前菜单项位置

//sleep for t seconds
static void wait(int t)  
{
    // 线程睡眠函数,参考资料:http://www.2cto.com/kf/201312/264724.htmlhttp://zh.cppreference.com/w/cpp/thread/sleep_for
    std::chrono::milliseconds dura( t * 1000 );
    std::this_thread::sleep_for( dura );
}

// 构造函数
TestController::TestController()
: _beginPos(Point::ZERO)  // 初始化:开始触摸点
{
    // add close menu
    // 右上角的关闭按钮
    auto closeItem = MenuItemImage::create(s_pathClose, s_pathClose, CC_CALLBACK_1(TestController::closeCallback, this) );
    auto menu =Menu::create(closeItem, NULL);

    // 设置关闭按钮的位置 
    menu->setPosition( Point::ZERO );
    closeItem->setPosition(Point( VisibleRect::right().x - 30, VisibleRect::top().y - 30));

    // add menu items for tests
    // 字体配置: 字体路径,字体大小
    TTFConfig ttfConfig("fonts/arial.ttf", 24);
    
    // 创建主菜单,添加菜单项
    _itemMenu = Menu::create();
    for (int i = 0; i < g_testCount; ++i)
    {
        auto label = Label::createWithTTF(ttfConfig, g_aTestNames[i].test_name);       
        auto menuItem = MenuItemLabel::create(label, CC_CALLBACK_1(TestController::menuCallback, this));

        _itemMenu->addChild(menuItem, i + 10000);  // 为了避免冲突,这里加10000
        menuItem->setPosition( Point( VisibleRect::center().x, (VisibleRect::top().y - (i + 1) * LINE_SPACE) ));
    }
    // 设置菜单的固定大小,无论视图如何缩放。
    _itemMenu->setContentSize(Size(VisibleRect::getVisibleRect().size.width, (g_testCount + 1) * (LINE_SPACE)));
    _itemMenu->setPosition(s_tCurPos);
    addChild(_itemMenu);

    addChild(menu, 1);

    // Register Touch Event
    auto listener = EventListenerTouchOneByOne::create();  // 创建一个单点触摸事件监听器,处理触摸事件逻辑 
    listener->setSwallowTouches(true);  //如果不加入此句消息依旧会向下传递
    
    listener->onTouchBegan = CC_CALLBACK_2(TestController::onTouchBegan, this);  // 触摸:开始。回调函数
    listener->onTouchMoved = CC_CALLBACK_2(TestController::onTouchMoved, this);  // 触摸:移动。回调函数
    
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);  // 将触摸监听添加到事件调度eventDispacher中

    auto mouseListener = EventListenerMouse::create();  // 创建一个鼠标响应事件
    mouseListener->onMouseScroll = CC_CALLBACK_1(TestController::onMouseScroll, this);  // 鼠标:滚动。回调函数
    _eventDispatcher->addEventListenerWithSceneGraphPriority(mouseListener, this);  // 将触摸监听添加到事件调度eventDispacher中
}

// 析构函数
TestController::~TestController()
{
}

// 菜单按钮回调
void TestController::menuCallback(Ref * sender)
{
    Director::getInstance()->purgeCachedData();  // 清除缓存的数据

    // get the userdata, it's the index of the menu item clicked
    auto menuItem = static_cast<MenuItem *>(sender);  // 转换类型
    int idx = menuItem->getLocalZOrder() - 10000;  // 获得点击菜单是第几个,addChild的时候加了10000,所以这里减去10000

    // create the test scene and run it
    // 获取父类为TestScene的xxx场景
    auto scene = g_aTestNames[idx].callback();  // 根据index获得数组元素,调用元素方法callback()返回创建的场景
    

    if (scene)  // 场景存在,运行这个场景
    {
        scene->runThisTest();  // 运行这个场景
        scene->release();  // 释放,因为用new生成的~~~
    }
}

// 关闭按钮回调,结束游戏
void TestController::closeCallback(Ref * sender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
    MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
    return;
#endif

    Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}

// 触摸:开始
bool TestController::onTouchBegan(Touch* touch, Event  *event)
{
    _beginPos = touch->getLocation();  // 记录触摸开始点
    return true;  // true:触摸成功
}

// 触摸:移动
void TestController::onTouchMoved(Touch* touch, Event  *event)
{
    auto touchLocation = touch->getLocation();  // 当前触摸点
    float nMoveY = touchLocation.y - _beginPos.y;  // y轴移动距离

    auto curPos  = _itemMenu->getPosition();  // 获得菜单项位置
    auto nextPos = Point(curPos.x, curPos.y + nMoveY);  // 计算移动后,菜单项位置

    if (nextPos.y < 0.0f)  // 如果移动后位置小于最小位置,则将移动后位置设置为:最小。
    {
        _itemMenu->setPosition(Point::ZERO);
        return;
    }

    // 如果移动后位置大于最大位置,则将移动后位置设置为:最大。
    if (nextPos.y > ((g_testCount + 1)* LINE_SPACE - VisibleRect::getVisibleRect().size.height))  
    {
        _itemMenu->setPosition(Point(0, ((g_testCount + 1)* LINE_SPACE - VisibleRect::getVisibleRect().size.height)));
        return;
    }

    _itemMenu->setPosition(nextPos);  // 设置菜单项位置
    _beginPos = touchLocation;  // 将当前触摸点位置设置为起始位置,以便下次计算
    s_tCurPos   = nextPos;  // 保存菜单项当前位置
}

// 鼠标:滚动(类似于onTouchMoved,这里就不解释了~~~)
void TestController::onMouseScroll(Event *event)
{
    auto mouseEvent = static_cast<EventMouse*>(event);
    float nMoveY = mouseEvent->getScrollY() * 6;

    auto curPos  = _itemMenu->getPosition();
    auto nextPos = Point(curPos.x, curPos.y + nMoveY);

    if (nextPos.y < 0.0f)
    {
        _itemMenu->setPosition(Point::ZERO);
        return;
    }

    if (nextPos.y > ((g_testCount + 1)* LINE_SPACE - VisibleRect::getVisibleRect().size.height))
    {
        _itemMenu->setPosition(Point(0, ((g_testCount + 1)* LINE_SPACE - VisibleRect::getVisibleRect().size.height)));
        return;
    }

    _itemMenu->setPosition(nextPos);
    s_tCurPos   = nextPos;
}

#if (CC_TARGET_PLATFORM != CC_PLATFORM_WP8) && (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT)
// 函数实现了控制台,用于文本输入输出
void TestController::addConsoleAutoTest()
{
    // 获得控制台
    auto console = Director::getInstance()->getConsole();
    
    static struct Console::Command autotest = {
        "autotest", 
        "testcpp autotest command, use -h to list available tests", 
        [](int fd, const std::string& args) 
        {
            Scheduler *sched = Director::getInstance()->getScheduler();
            if(args == "help" || args == "-h")
            {
                const char msg[] = "usage: autotest ActionsTest\n\tavailable tests: ";
                send(fd, msg, sizeof(msg),0);
                send(fd, "\n",1,0);
                for(int i = 0; i < g_testCount; i++)
                {
                    send(fd, "\t",1,0);
                    send(fd, g_aTestNames[i].test_name, strlen(g_aTestNames[i].test_name)+1,0);
                    send(fd, "\n",1,0);
                }
                const char help_main[] = "\tmain, return to main menu\n";
                send(fd, help_main, sizeof(help_main),0);

                const char help_next[] = "\tnext, run next test\n";
                send(fd, help_next, sizeof(help_next),0);
                
                const char help_back[] = "\tback, run prev test\n";
                send(fd, help_back, sizeof(help_back),0);
                
                const char help_restart[] = "\trestart, restart current test\n";
                send(fd, help_restart, sizeof(help_restart),0);
                return;
            }
            if(args == "main")
            {
                
                sched->performFunctionInCocosThread( [&]()
                {
                    auto scene = Scene::create();
                    auto layer = new TestController();
                    scene->addChild(layer);
                    layer->release();
                    Director::getInstance()->replaceScene(scene);
                    cocostudio::ArmatureDataManager::destroyInstance();
                } );
                return;
            }
            const char msg_notest[] = "autotest: can't detect running test.\n";
            AppDelegate* app = (AppDelegate *)Application::getInstance();
            BaseTest* currentTest = app->getCurrentTest();
            if(args == "next")
            {
                if(currentTest != nullptr)
                {
                    //currentTest->nextCallback(nullptr);
                    sched->performFunctionInCocosThread( [&](){
                            currentTest->nextCallback(nullptr);
                        } );
                }
                else
                {
                    send(fd, msg_notest, sizeof(msg_notest),0);
                }
                return;
            }
            if(args == "back")
            {
                if(currentTest != nullptr)
                {
                    sched->performFunctionInCocosThread( [&](){
                        currentTest->backCallback(nullptr);
                    } );
                }
                else
                {
                    send(fd, msg_notest, sizeof(msg_notest),0);
                }
                return;
            }

            if(args == "restart")
            {
                if(currentTest != nullptr)
                {
                    sched->performFunctionInCocosThread( [&](){
                        currentTest->restartCallback(nullptr);
                    } );
                }
                else
                {
                    send(fd, msg_notest, sizeof(msg_notest),0);
                }
                return;
            }

            if(args == "run")
            {
                for (int i = 0; i < g_testCount; i++)
                {
                    // create the test scene and run it
                    std::string  msg("autotest: running test:");
                    msg += g_aTestNames[i].test_name;
                    send(fd, msg.c_str(), strlen(msg.c_str()),0);
                    send(fd, "\n",1,0);

                    currentController = &g_aTestNames[i];
                    sched->performFunctionInCocosThread( [&](){
                        auto scene = currentController->callback();
                        if(scene)
                        {
                            scene->runThisTest();
                            scene->release();
                        }
                    } );
                    wait(1);
                    BaseTest* firstTest = app->getCurrentTest();
                    if(firstTest == nullptr)
                    {
                        continue;
                    }
                    std::string  t1("");
                    t1 += firstTest->subtitle();
                    send(fd, t1.c_str(), strlen(t1.c_str()),0);
                    send(fd, "\n",1,0);
                    wait(2);

                    while(1)
                    {
                        //currentTest->nextCallback(nullptr);
                        sched->performFunctionInCocosThread( [&](){
                            BaseTest *t = app->getCurrentTest();
                            if(t != nullptr)
                            {
                                t->nextCallback(nullptr);
                            }
                        } );
                        wait(1);
                        BaseTest * curTest = app->getCurrentTest();
                        if(curTest == nullptr)
                        {
                            break;
                        }
                        std::string  title("");
                        title += curTest->subtitle();
                        send(fd, title.c_str(), strlen(title.c_str()),0);
                        send(fd, "\n",1,0);
                        wait(2);

                        if(t1 == title)
                        {
                            break;
                        }
                    }
                }
                return;
            }

            for(int i = 0; i < g_testCount; i++)
            {
                if(args == g_aTestNames[i].test_name)
                {
                    currentController = &g_aTestNames[i];
                    std::string  msg("autotest: running test:");
                    msg += args;
                    send(fd, msg.c_str(), strlen(msg.c_str()),0);
                    send(fd, "\n",1,0);

                        
                    sched->performFunctionInCocosThread( [&](){
                        auto scene = currentController->callback();
                        if(scene)
                        {
                            scene->runThisTest();
                            scene->release();
                        }
                    } );
                    return;
                }
            }

            //no match found,print warning message
            std::string  msg("autotest: could not find test:");
            msg += args;
            send(fd, msg.c_str(), strlen(msg.c_str()),0);
            send(fd, "\n",1,0);
        }
        
    };
    console->addCommand(autotest);
}
#endif

好吧,这篇文章勉强完成。星月在这里给大家道歉,写这篇文章时没有考虑到会涉及这么多知识点,希望大家指出错误的敌方,星月会不断改变~~~

// 函数实现了控制台,用于文本输入输出
void TestController::addConsoleAutoTest()

这个函数星月没有解释,不是因为懒(星月很勤快的~~~,小白:噗!!!群众的眼睛是雪亮的!!!!)...咳,这个星月也没有研究过,所以就不解释误导大家。

如果大家有这个方法的解释,希望能告诉星月,让星月也学习下,在此不尽感激!!!

 

作者使用 cocos2d-x 3.0 示例代码分析,未经作者允许,请勿转载!在此谢谢各位手下留情~~~

本文没有获得作者本人同意,不得转载,否则必追究相关责任。转载请注明出处!!~~

原文地址:http://www.cnblogs.com/wodehao0808/p/4045327.html

posted @ 2014-10-23 18:00  星月相随  阅读(1194)  评论(0编辑  收藏  举报