Cocos2d-x学习笔记:完全掌握JS API与游戏项目开发 (未来书库,触控未来官方教材)
上QQ阅读APP看书,第一时间看更新

4.2 第一个Cocos2d-x JS绑定游戏

我们编写第一个Cocos2d-x JS绑定程序,命名为HelloJS,从该工程开始学习其他内容。

4.2.1 创建工程

创建Cocos2d-x JS绑定工程可以通过Cocos2d-x提供的命令工具cocos实现,但这种方式不能与WebStorm或Cocos Code IDE集成开发工具很好地集成,不便于程序编写和调试。由于Cocos Code IDE工具是专门为Cocos2d-x JS绑定和Cocos2d-x Lua绑定开发设计的,因此使用Cocos Code IDE工具可以很方便地创建Cocos2d-x JS绑定工程。

下面介绍使用Cocos Code IDE创建Cocos2d-x JS绑定工程的具体过程,在欢迎界面中单击Create New Project按钮,或选择菜单File→New→Project,弹出图4-4所示的对话框。

图4-4 项目类型选择对话框

在对话框中选择Cocos→Cocos JS,然后单击Next按钮进入图4-5所示的配置运行环境对话框,在该对话框中可以配置项目运行时信息。Orientation项目是配置模拟器的朝向,其中landscape是横屏显示,portriat是竖屏显示。在Desktop Windows Initializing→Selection中可以选择模拟器,选择完成后单击Next按钮进入图4-6所示的文件保存对话框。

图4-5 配置运行环境对话框

在图4-6所示的文件保存对话框的Project name中输入文件名,本例是HelloJS。在Project location中选择文件保存的位置。完成后单击Finish按钮,创建的工程如图4-7所示。

图4-6 文件保存对话框

图4-7 创建工程之后

从图4-7可见,IntelliJ IDEA与WebStorm的界面、操作菜单和功能按钮基本一样,因此IntelliJ IDEA基本操作可以参考第2章的相关内容,这里不再赘述。

4.2.2 在Cocos Code IDE中运行

创建好工程后,我们可以测试一下,在左边的工程导航面板中选中工程名(HelloJS),右键菜单中选择Run As→'HelloJS'或单击工具栏中的运行按钮,运行刚刚创建的工程,运行结果如图4-8所示。

图4-8 运行工程界面

4.2.3 在WebStorm中运行

Cocos Code IDE插件工具提供本地运行,即Cocos2d-x JS绑定程序通过JSB在本地运行。如果需要测试Web浏览器上运行情况,而且需要在Web环境下能够调试,可以使用WebStorm工具。由于我们已经在Cocos Code IDE创建了工程,这里不需要再创建了。由于Cocos Code IDE插件是基于IntelliJ IDEA工具,IntelliJ IDEA与WebStorm同源,所以WebStorm可以直接打开Cocos Code IDE创建的工程。

WebStorm打开界面如图4-9所示,HelloJS是要运行的工程,右键选择HelloJS中的index.html文件就可以运行了,具体运行过程参考2.1.3节。调试模式运行结果如图4-10所示。

图4-9 打开工程界面

图4-10 在浏览器中调试模式运行

4.2.4 工程文件结构

我们创建的HelloJS工程已经能够运行起来了,下面介绍HelloJS工程中的文件结构。使用Cocos Code IDE打开HelloJS工程,左侧的导航面板如图4-11所示。

图4-11 HelloJS工程中的文件结构

在图4-11所示的导航面板中,res文件夹存放资源文件,src文件夹是主要的程序代码,其中的app.js是实现游戏场景的JavaScript文件,resource.js定义资源对应的变量。HelloJS根目录下还有config.json、project.json、index.html和main.js。config.json保存模拟器运行配置信息,它们是在我们创建工程时生成的;project.json是项目的配置信息;index.html是Web游戏的首页;main.js是与首页index.html对应的JavaScript文件。我们在开发游戏时只需要关心res和src文件夹中的内容就可以了,其他的文件和文件夹不是关注重点。

4.2.5 代码解释

HelloJS工程中有很多文件。下面详细解释它们内部的代码:

1.index.html文件

index.html文件只有在Web浏览器上运行才会启动,index.html代码如下:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>Cocos2d-html5 Hello World test</title>
        <link rel="icon" type="image/GIF" href="res/favicon.ico"/>
        <meta name="viewport" content="width=480, initial-scale=1">
        <meta name="apple-mobile-web-app-capable" content="yes"/>        ①
        <meta name="full-screen" content="yes"/>
        <meta name="screen-orientation" content="portrait"/>
        <meta name="x5-fullscreen" content="true"/>
        <meta name="360-fullscreen" content="true"/>                    ②
        <style>
            body, canvas, div {
                -moz-user-select: none;
                -webkit-user-select: none;
                -ms-user-select: none;
                -khtml-user-select: none;
                -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
            }
        </style>
    </head>
    <body style="padding:0; margin: 0; background: #000;">
    <script src="res/loading.js"></script>
    <canvas id="gameCanvas" width="480" height="720"></canvas>                ③
    <script src="frameworks/cocos2d-html5/CCBoot.js"></script>④
    <script cocos src="main.js"></script>    ⑤
    </body>
    </html>

上述代码第①~②行是设置网页的meta信息,meta信息是网页基本信息,这些设置能使index.html网页很好地在移动设备上显示。

第③行代码放置一个canvas标签,canvas标签是HTML5提供的,通过JavaScript可以在Canvas上绘制2D图形。Cocos2d-x游戏在网页上运行,游戏场景都是通过Canvas渲染出来的,Cocos2d-x的本地运行游戏场景是通过OpenGL渲染出来的。事实上,HTML5也有类似于OpenGL渲染技术——WebGL,但是考虑到浏览器的支持程度不同,Cocos2d-x没有采用WebGL渲染而是采用了Canvas渲染,虽然Canvas渲染速度不及WebGL,但是一般的网页游戏都能满足要求。

第④行代码是导入JavaScript文件CCBoot.js,我们不需要维护该文件。第⑤行代码是导入JavaScript文件main.js,我们需要维护该文件。

2.main.js文件

main.js负责启动游戏场景,无论是在Web浏览器运行还是在本地运行,都是通过该文件启动游戏场景的,main.js代码如下:

    cc.game.onStart = function(){                ①
        if(!cc.sys.isNative && document.getElementById("cocosLoading"))
            document.body.removeChild(document.getElementById("cocosLoading"));
    
        // 如果为true则在iOS下开启Retina显示支持,Android下默认是关闭,这是为了提升性能
        cc.view.enableRetina(cc.sys.os === cc.sys.OS_IOS ? true : false);
        // 调整网页viewport(视口)
        cc.view.adjustViewPort(true);
        // 设置屏幕适配策略和设计分辨率大小
        cc.view.setDesignResolutionSize(960, 640, cc.ResolutionPolicy.SHOW_ALL);        ②
        //  重新调整浏览器大小
        cc.view.resizeWithBrowserSize(true);
        // 加载资源
        cc.LoaderScene.preload(g_resources, function () {            ③
            cc.director.runScene(new HelloWorldScene());            ④
        }, this);
    };
    cc.game.run();                        ⑤

上述代码第①行是启动游戏,cc.game是一个游戏启动对象。第②行是设置屏幕适配策略和设计分辨率大小,cc.ResolutionPolicy.SHOW_ALL是屏幕适配策略。

第③行代码是加载游戏场景所需要的资源,其中g_resources参数是加载资源的数组,该数组是在src/resource.js文件中定义的。第④行代码是运行HelloWorldScene场景,cc.director是导演对象,运行HelloWorldScene场景会进入到该场景。第⑤行代码cc.game.run()是运行游戏启动对象。

3.project.json文件

项目配置信息project.json文件代码如下:

    {
        "project_type": "javascript",
    
        "debugMode" : 1,
        "showFPS" : true,                           ①
        "frameRate" : 60,                           ②
        "noCache" : false,
        "id" : "gameCanvas",
        "renderMode" : 0,
        "engineDir":"frameworks/cocos2d-html5",
    
        "modules" : ["cocos2d", "cocostudio"],    ③
    
        "jsList" : [                               ④
            "src/resource.js",                      ⑤
            "src/app.js"                            ⑥
        ]
    }

project.json文件采用JSON字符串表示,我们重点关注有标号的语句,其中第①行代码设置是否显示帧率调试信息,帧率调试就是显示在左下角的文字信息。第②行代码是设置帧率为60,即屏幕每1/60秒刷新一次。第③行代码是加载游戏引擎的模块,cocos2d-html5 Framework中有很多模块,模块的定义是在HelloJS\frameworks\cocos2d-html5\moduleConfig.json,我们在资源管理器中才能看到该文件,这些模块在场景启动的时候加载,因此一定要根据需要导入,否则造成资源的浪费。例如,我们再添加一个chipmunk物理引擎模块,第③行代码可以修改成如下形式:

    "modules" : ["cocos2d","chipmunk","cocostudio"]

第④~⑥行代码是声明需要加载的JavaScript文件,这里的文件主要是我们编写的,我们每次添加一个JavaScript文件到工程中,就需要在此处添加声明。

4.config.json文件

只有在Cocos Code IDE中运行才需要该文件,用于配置模拟器运行信息。该文件在工程发布时和Web环境下运行时都没有用处。但如果想在Cocos Code IDE中运行,并改变模拟器大小和方向,可以修改该文件,config.json文件代码如下:

    {
      "init_cfg": {                                                           ①
        "isLandscape": true,                                                  ②
        "name": "HelloJS",                                                    ③
        "width": 960,                                                         ④
        "height": 640,                                                        ⑤
        "entry": "main.js",                                                   ⑥
        "consolePort": 6050,
        "debugPort": 5086,
        "forwardConsolePort": 10088,
        "forwardUploadPort": 10090,
        "forwardDebugPort": 10086
      },
      "simulator_screen_size": [
        {
          "title": "iPhone 3Gs (480x320)",
          "width": 480,
          "height": 320
        },
        ……
      ]
    }

上述代码第①行是初始配置信息,第②行是设置横屏显示还是竖屏显示,第③行name属性是设置模拟器上显示的标题,第④和第⑤行是设置屏幕的宽和高,第⑥行是设置入口文件。

5.resource.js文件

resource.js文件是在src文件夹中,处于该文件夹中的文件由用户来维护。在resource.js文件中定义资源对应的变量。resource.js文件代码如下:

    var res = {                            ①
        HelloWorld_png : "res/HelloWorld.png",
        MainScene_json : "res/MainScene.json"
    };
    
    var g_resources = [];            ②
    for (var i in res) {
        g_resources.push(res[i]);     ③
    }

上述第①行代码是定义JSON变量res,它为每一个资源文件定义一个别名,在程序中访问资源,资源名不要“写死”“写死”称为硬编码(Hard Code或Hard Coding),硬编码指的是把输出或输入的相关参数(例如路径、输出的形式或格式)直接以常量的方式书写在源代码中。——引自维基百科http://zh.wikipedia.org/zh-cn/%E5%AF%AB%E6%AD%BB,而是通过一个可配置的别名访问,这样当环境变化之后修改起来很方便。

第②行代码是定义资源文件集合变量g_resources,它的内容是通过第③行代码把res变量中的资源文件循环添加到g_resources中。当然,我们可以逐一添加:

    var g_resources = [
        res.HelloWorld_png,
        res. MainScene_json
    ];

放在g_resources变量的资源,会在场景中加载,在Web浏览器下运行时如果找不到加载的资源会报出404错误。

6.app.js文件

app.js文件是在src文件夹中,处于该文件夹中的文件是由用户来维护的,图4-8和图4-10所示的场景是在app.js中实现的,app.js代码如下:

    var HelloWorldLayer = cc.Layer.extend({                  ①
        sprite:null,           //定义一个精灵属性
        ctor:function () {      //构造方法                 ②
            //////////////////////////////
            // 1. super init first
            this._super();      //初始化父类
    
            /////////////////////////////
            var size = cc.winSize; //获得屏幕大小
    
            var mainscene = ccs.load(res.MainScene_json);     ③
            this.addChild(mainscene.node);                    ④
    
            return true;
        }
    });                                                       ⑤
    
    var HelloWorldScene = cc.Scene.extend({                   ⑥
        onEnter:function () {                                 ⑦
            this._super();                                    ⑧
            var layer = new HelloWorldLayer();                ⑨
            this.addChild(layer);                             ⑩
        }
    });

我们在app.js文件中声明了两个类HelloWorldScene(见代码第①行)和HelloWorldLayer(见代码第⑥行),然后在HelloWorldScene中实例化HelloWorldLayer(见代码第⑨行)。HelloWorldScene是场景,HelloWorldLayer是层,场景包含若干个层。关于场景和层,我们会在后面具体介绍。

第②~⑤行代码是声明构造方法。第③行代码通过场景文件MainScene_json创建场景。场景文件MainScene_json是通过Cocos Studio工具创建和设计的。第④行代码通过this.addChild(mainscene.node)语句将场景对象添加到HelloWorldLayer层中。

第⑦行代码是声明onEnter方法,它是在进入HelloWorldScene场景时回调的。onEnter方法是重写父类的方法,我们必需通过this._super()语句调用父类的onEnter方法(见代码第⑧行)。第⑩行代码是将HelloWorldLayer层放到HelloWorldScene场景中。

4.2.6 重构HelloJS案例

4.2.5节介绍的HelloJS案例中的场景是通过Cocos Studio工具创建和设计的,由于Cocos Studio的内容超出了本书介绍的范围,故不再使用Cocos Studio工具创建场景,重构HelloJS案例。

重构app.js代码如下:

    var HelloWorldLayer = cc.Layer.extend({
        sprite:null,                          //定义一个精灵属性
        ctor:function () {                      //构造方法
            this._super();                  //初始化父类
            var size = cc.winSize;           //获得屏幕大小
            var closeItem = new cc.MenuItemImage(                       ①
                res.CloseNormal_png,
                res.CloseSelected_png,
                function () {                                            ②
                    cc.log("Menu is clicked!");
                }, this);
            closeItem.attr({                                            ③
                x: size.width - 20,
                y: 20,
                anchorX: 0.5,
                anchorY: 0.5
            });                                                        ④
    
            var menu = new cc.Menu(closeItem);   //通过closeItem菜单项创建菜单对象
            menu.x = 0;                                                ⑤
            menu.y = 0;                                                ⑥
            this.addChild(menu, 1); //把菜单添加到当前层上
    
            var helloLabel = new cc.LabelTTF("Hello World", "Arial", 38);//创建标签对象
            helloLabel.x = size.width / 2;
            helloLabel.y = 0;
            this.addChild(helloLabel, 5);
            this.sprite = new cc.Sprite(res.HelloWorld_png); //创建精灵对象
            this.sprite.attr({
                x: size.width / 2,
                y: size.height / 2,
                scale: 0.5,
                rotation: 180
            });
            this.addChild(this.sprite, 0);
    
            this.sprite.runAction(                            ⑦
                cc.sequence(
                    cc.rotateTo(2, 0),
                    cc.scaleTo(2, 1, 1)
                )
            );   //在精灵对象上执行一个动画
            helloLabel.runAction(                            ⑧
                cc.spawn(
                    cc.moveBy(2.5, cc.p(0, size.height - 40)),
                    cc.tintTo(2.5,255,125,0)
                )
            );   //在标签对象上执行一个动画
            return true;
        }
    });
    
    var HelloWorldScene = cc.Scene.extend({
        onEnter:function () {
            this._super();
            var layer = new HelloWorldLayer();
            this.addChild(layer);  //把HelloWorldLayer层放到HelloWorldScene场景中
        }
    });

上述代码第①~④行是创建一个图片菜单项对象,单击该菜单项的时候回调function方法。

提示 cc.MenuItemImage中的res.CloseNormal_png和res.CloseSelected_png变量是在resource.js文件中定义的资源文件别名。后面res.开通变量都是资源文件的别名,不再详细解释。

第②行代码是菜单事件处理函数,其中cc.log("Menu is clicked!")语句是日志输出。

第③行代码是菜单项对象的位置,其中closeItem.attr({…})语句可以设置多个属性,多个属性设置采用JSON格式表示,x属性表示x轴坐标,y属性表示y轴坐标,anchorX表示x轴锚点,anchorY表示y轴锚点。关于锚点的概念后面会具体介绍。关于精灵x和y轴属性,我们也可以通过第⑤~⑥行代码的方式设置。

第⑦行和第⑧行代码是执行精灵动作。关于精灵动作,我们将在后面章节详细介绍。