cocos2d-js解析官方js-test实例入口

继续上一篇,搭建好cocos2d-js环境后,主要是html5环境,接下来步入入门阶段,许多人都说官网demo是最好的入门资料,今天就剖析官风提供的js-test入口,界面如下:
看图片

这上面有个关闭按钮和一个列表,列表列出了demo中所有的功能演示,这个js-tests工程在cocos2d-js的SDK中,以前是在samples目录下,现在最新版的放在tests目录中,目录结构如下:
目录结构

我们切换到目录js-tests下,在终端运行:cocos run -p web就能打开浏览器查看效果,如果你部署了服务器的话,可以把tests和web目录直接拷贝到服务器目录下,访问对应的目录也能查看效果,注意,要拷贝tests和web目录,因为js-tests中用到了web目录及cpp-tests目录下的资源,如果不确定,把cocos2d-x-3.x.x目录全拷贝吧,也可以做个虚拟目录指向这个目录。
查看效果后,接下来分析主要的几个文件,在此列出你要分析的几个文件,即是需要我们手动修改维护的文件:index.html(首页,入口页),main.js(cocos2d-js的启动与入口),project.json(项目的配置文件),res(资源目录),src(源文件存放目录,一般是js文件,一般有app.js,resource.js)。
1.index.html文件,这里给出源码:


<html>
<head>
    <meta charset="utf-8">
    <title>Cocos2d-HTML5 Test Casestitle>
    <link rel="icon"
          type="image/GIF"
          href="../cpp-tests/Resources/Images/favicon.ico"/>
head>
<body style="text-align: center;background: #f2f6f8;">
<img style="clear:both;margin-bottom: 20px" src="../cpp-tests/Resources/Images/cocos2dbanner.png"/>
<div>div>
<div style="display:inline-block;width:auto; margin: 0 auto; background: black; position:relative; border:5px solid black; border-radius: 10px; box-shadow: 0 5px 50px #333">
    
    
    <canvas id="gameCanvas" width="800" height="450">canvas> *(1)*
div>
<script src="../../web/CCBoot.js">script>*(2)*
<script src="main.js">script>*(3)*
body>
html>

在这里注意三个地方,第一个标签canvas,id为gameCanvas,id会在project.json中配置用到。
第二个../../web/CCBoot.js,注意他的路径,此文件不需要我们维护。
第三个main.js,游戏的真正入口函数来了。

2.介绍下project.json项目配置文件,文件太大,截图说明下:
看键头

从向往下:第一个是否显示左下角FPS的信息,自己测试。第二个就是index.html中canvas的id 。第三个引擎的目录,注意他的路径,第四个使用到的模块,注意在引擎目录下查找,最后个键头js文件的列表,如果你有自己的js文件,请记得添加。

3.你们在看helloword项目是,看到有resource.js文件,里面定义了用到的资源,但是这里没有这个文件,他把资源定义到了其他文件中,这里定义到src/tests_resources.js中,看下他的截图:
看键头

如图,第一个键头指明了js文件存放的路径,注意if判断条件,他是web浏览器才执行的,不是的话情况另当别论,不过本人分析的就是html5的,所以他就进来了,第二个键头指示资源的定义,他使用了相对路径,注意他的res路径指向了tests/cpp-tests/Resources,这个在main.js中指定,到时在说明。这就是资源的定义,代替了我们常见的resource.js文件。

4.进入到main.js,真正的入口,看下他的源码:

if(cc.sys){
    var scene3SearchPaths = cc.sys.localStorage.getItem("Scene3SearchPaths");
    //html5项目判断不成立,直接跳过,想了解请查看api
    if (scene3SearchPaths)
        jsb.fileUtils.setSearchPaths(JSON.parse(scene3SearchPaths));
}

cc.game.onStart = function(){
    //是否支持retina屏
    cc.view.enableRetina(false);
    //判断是不是本地化的还是web的,这里判断为否,直接查看else
    if (cc.sys.isNative) {
        var resolutionPolicy = (cc.sys.os == cc.sys.OS_WP8 || cc.sys.os == cc.sys.OS_WINRT) ? cc.ResolutionPolicy.SHOW_ALL : cc.ResolutionPolicy.FIXED_HEIGHT;
        cc.view.setDesignResolutionSize(800, 450, resolutionPolicy);
        cc.view.resizeWithBrowserSize(true);
        var searchPaths = jsb.fileUtils.getSearchPaths();
        searchPaths.push('script');
        searchPaths.push('src');
        var paths = [
            'res/resjs',
            'res',
            'res/scenetest',
            'res/scenetest/ArmatureComponentTest',
            'res/scenetest/AttributeComponentTest',
            'res/scenetest/BackgroundComponentTest',
            'res/scenetest/EffectComponentTest',
            'res/scenetest/LoadSceneEdtiorFileTest',
            'res/scenetest/ParticleComponentTest',
            'res/scenetest/SpriteComponentTest',
            'res/scenetest/TmxMapComponentTest',
            'res/scenetest/UIComponentTest',
            'res/scenetest/TriggerTest'
        ];
        for (var i = 0; i < paths.length; i++) {
            searchPaths.push(paths[i]);
        }
        jsb.fileUtils.setSearchPaths(searchPaths);
    }
    else
    {
        //注意这里,他设置了res的路径,即资源目录,在资源文件中定义时访问的是这个目录下文件
        cc.loader.resPath = '../cpp-tests/Resources'
    }
    //预加载资源,g_resources在test_resource.js中定义,加载完成后会调用第二个参数,一个匿名函数
    cc.LoaderScene.preload(g_resources, function () {
        //判断条件不成立,进入else
        if(window.sideIndexBar && typeof sideIndexBar.start === 'function'){
            sideIndexBar.start();
        }else{
            //这里设置场景,添加layer,运行场景,查看TestController类做了什么,他在test-main.js中定义
            var scene = new cc.Scene();
            scene.addChild(new TestController());
            cc.director.runScene(scene);
        }
    }, this);
};
//运行游戏
cc.game.run();

看代码,运行逻辑注释已经解释了,这是针对浏览器的,其他的情况没有去分析,其他情况也就是设置资源的搜索路径,现在理着他运行的步骤一步一步跟踪他到底做了什么。

5.从main.js中看到他创建了个类TestController添加到主场景中,接下来查看这个类都做了什么,他的路径为:
js-tests/src/tests-main.js。查看可知道他继承了类LayerGradient,这是个支持两种颜色的渐变的层,单颜色请查看LayerColor类。这里定义了一些全局变量和类的属性,在此不一一列举了,请看源文件,要分析这个类做了什么,就看下他的生命周期中相应的回调函数,第一个构造函数(ctor),第二个onEnter(进入函数),看下构造函数的源码,解释放在注释中:

//下面三个属性在类中定义
_itemMenu:null,
    _beginPos:0,
    isMouseDown:false,
    //构造函数
    ctor:function() {   
        //两种渐变的颜色,可修改看效果   
        this._super(cc.color(0,0,0,255), cc.color(0x46,0x82,0xB4,255));

        // globals 这两个为全局属性
        director = cc.director;
        winSize = director.getWinSize();

        // add close menu 关闭按钮参数一,二为两种状态的图标,在资源文件中定义,第三个点击时的回调函数
        var closeItem = new cc.MenuItemImage(s_pathClose, s_pathClose, this.onCloseCallback, this);
        //设置他的坐标,左下角为原点,向右X轴增大,向上Y轴增大,这个在右上角
        closeItem.x = winSize.width - 30;
        closeItem.y = winSize.height - 30;
        //动画是否自动切换图标
        var subItem1 = new cc.MenuItemFont("Automated Test: Off");
        subItem1.fontSize = 18;
        var subItem2 = new cc.MenuItemFont("Automated Test: On");
        subItem2.fontSize = 18;
        //自动切换按钮属性设置,回调函数,坐标,是否可见,这里设置不可见,我们看不到效果,请设置可见查看效果
        var toggleAutoTestItem = new cc.MenuItemToggle(subItem1, subItem2);
        toggleAutoTestItem.setCallback(this.onToggleAutoTest, this);
        toggleAutoTestItem.x = winSize.width - toggleAutoTestItem.width / 2 - 10;
        toggleAutoTestItem.y = 20;
        toggleAutoTestItem.setVisible(false);
        if( autoTestEnabled )
            toggleAutoTestItem.setSelectedIndex(1);


        var menu = new cc.Menu(closeItem, toggleAutoTestItem);//pmenu is just a holder for the close button
        menu.x = 0;
        menu.y = 0;

        // add menu items for tests
        this._itemMenu = new cc.Menu();//item menu is where all the label goes, and the one gets scrolled
        //d在这里添加主界面中,各个demo的入口,其中testNames是个数组,存放了对象,接下来在分析
        for (var i = 0, len = testNames.length; i < len; i++) {
            var label = new cc.LabelTTF(testNames[i].title, "Arial", 24);

            var menuItem = new cc.MenuItemLabel(label, this.onMenuCallback, this);
            this._itemMenu.addChild(menuItem, i + 10000);
            menuItem.x = winSize.width / 2;
            menuItem.y = (winSize.height - (i + 1) * LINE_SPACE);

            // enable disable
            if ( !cc.sys.isNative) {
                if( 'opengl' in cc.sys.capabilities ){
                    menuItem.enabled = (testNames[i].platforms & PLATFORM_HTML5) | (testNames[i].platforms & PLATFORM_HTML5_WEBGL);
                }else{
                    menuItem.setEnabled( testNames[i].platforms & PLATFORM_HTML5 );
                }
            } else {
                if (cc.sys.os == cc.sys.OS_ANDROID) {
                    menuItem.setEnabled( testNames[i].platforms & ( PLATFORM_JSB | PLATFROM_ANDROID ) );
                } else if (cc.sys.os == cc.sys.OS_IOS) {
                    menuItem.setEnabled( testNames[i].platforms & ( PLATFORM_JSB | PLATFROM_IOS) );
                } else if (cc.sys.os == cc.sys.OS_OSX) {
                    menuItem.setEnabled( testNames[i].platforms & ( PLATFORM_JSB | PLATFORM_MAC) );
                } else {
                    menuItem.setEnabled( testNames[i].platforms & PLATFORM_JSB );
                }
            }
        }

        this._itemMenu.width = winSize.width;
        this._itemMenu.height = (testNames.length + 1) * LINE_SPACE;
        this._itemMenu.x = curPos.x;
        this._itemMenu.y = curPos.y;
        this.addChild(this._itemMenu);
        this.addChild(menu, 1);

        // 'browser' can use touches or mouse. 事件的处理,即滚动处理
        // The benefit of using 'touches' in a browser, is that it works both with mouse events or touches events
        if ('touches' in cc.sys.capabilities)
            cc.eventManager.addListener({
                event: cc.EventListener.TOUCH_ALL_AT_ONCE,
                onTouchesMoved: function (touches, event) {
                    var target = event.getCurrentTarget();
                    var delta = touches[0].getDelta();
                    target.moveMenu(delta);
                    return true;
                }
            }, this);
        else if ('mouse' in cc.sys.capabilities) {
            cc.eventManager.addListener({
                event: cc.EventListener.MOUSE,
                onMouseMove: function (event) {
                    if(event.getButton() == cc.EventMouse.BUTTON_LEFT)
                        event.getCurrentTarget().moveMenu(event.getDelta());
                },
                onMouseScroll: function (event) {
                    var delta = cc.sys.isNative ? event.getScrollY() * 6 : -event.getScrollY();
                    event.getCurrentTarget().moveMenu({y : delta});
                    return true;
                }
            }, this);
        }

    }

代码注释说最大部分功能,其他的查看源码,构造函数完成后,会调用onEnter函数,下面给出他的源码:

onEnter:function(){
       //调用父类方法
        this._super();
        //设置主界面菜单y坐标
        this._itemMenu.y = TestController.YOffset;
    },

接下来查看testNames数组的结构:

var testNames = [
    {
        title:"ActionManager Test",
        platforms: PLATFORM_ALL,
        linksrc:"src/ActionManagerTest/ActionManagerTest.js",
        testScene:function () {
            return new ActionManagerTestScene();
        }
    },
    {
        title:"Actions Test",
        platforms: PLATFORM_ALL,
        linksrc:"src/ActionsTest/ActionsTest.js",
        testScene:function () {
            return new ActionsTestScene();
        }
    }

到了这一步,主界面已经显示出来了,现在就是最后一步,当点击其中一项是,他又干了什么,即回调函数onMenuCallback,查看源码:

onMenuCallback:function (sender) {
        TestController.YOffset = this._itemMenu.y;
        var idx = sender.getLocalZOrder() - 10000;
        // get the userdata, it's the index of the menu item clicked
        // create the test scene and run it

        autoTestCurrentTestName = testNames[idx].title;

        var testCase = testNames[idx];
        var res = testCase.resource || [];
        cc.LoaderScene.preload(res, function () {
            var scene = testCase.testScene();
            console.log(scene);
            if (scene) {
                scene.runThisTest();
            }
        }, this);
    }

到了这一步,接下来要分析的是scene.runThisTest()函数做了什么,怎么切换场景了,自己选择感兴趣地模块分析吧。GOOD LUCK!!!!!1

你可能感兴趣的:(cocos2d-js)