cocos2d-x-html5之遊戲啓動

接觸cocos2dx有5年多來,以後可能要切換到creator了。所以打算重新學習一下cocos2dx源碼,並記錄一下。

今天我們來講一下web版本是怎麼啓動,首先看下模版工程的文件結構,其中index.html爲入口。
在這裏插入圖片描述
接下來我們看下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=321,user-scalable=no" />
    <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>
    <!--加載腳本-->
    <script src="../CCBoot.js"></script>
    <!--程序入口-->
    <script src="main.js"></script>
</head>

<body style="padding:0; margin: 0; background: #000;">
    <script src="res/loading.js"></script>
    <canvas id="gameCanvas" width="321" height="480"></canvas>
</body>

</html>

可以看到這邊是加載了CCBoot.js和main.js文件,其中CCBoot.js是引擎提供的,裏面包含了遊戲啓動的流程,main.js是每個項目組自己寫的。

接下來我們看下main.js的源碼:

// 重寫 onStart 函數,執行cc.game.run後,最終執行這裏
cc.game.onStart = function () {
    // 如果index.html引用了loading.js,這裏需要移除
    if (!cc.sys.isNative && document.getElementById("cocosLoading")) //If referenced loading.js, please remove it
        document.body.removeChild(document.getElementById("cocosLoading"));

    // 聲明並定義設計分辨率(豎屏)
    var designSize = cc.size(480, 800);
    // 屏幕分辨率
    var screenSize = cc.view.getFrameSize();
    // 如果不是原生,且高度小於800
    if (!cc.sys.isNative && screenSize.height < 800) {
        // 修改設計分辨率
        designSize = cc.size(320, 480);
        cc.loader.resPath = "res/Normal";
    } else {
        cc.loader.resPath = "res/HD";
    }
    // 等比拉伸,會留黑邊
    cc.view.setDesignResolutionSize(designSize.width, designSize.height, cc.ResolutionPolicy.SHOW_ALL);

    //load resources
    // 運行loaderScene場景,加載資源成功後,運行回調函數
    cc.LoaderScene.preload(g_resources, function () {
        // 運行自己的場景,在src/myApp.js
        cc.director.runScene(new MyScene());
    }, this);
};
// 啓動遊戲,該方法在 CCBoot.js裏面實現
cc.game.run();

流程可以看註釋,從代碼中我們看到加載資源的時候,是運行了cc.LoaderScne.preload來創建一個過渡場景,等資源加載成功後,運行自己的場景 MyScene。

接下來我們看下 CCLoaderScene.js的源碼

/**
 * <p>cc.LoaderScene is a scene that you can load it when you loading files</p>
 * <p>cc.LoaderScene can present thedownload progress </p>
 * @class
 * @extends cc.Scene
 * @example
 * var lc = new cc.LoaderScene();
 */
// 用於下載文件時顯示的場景
cc.LoaderScene = cc.Scene.extend({
    _interval: null,
    _label: null,
    _logo: null,
    _className: "LoaderScene",
    cb: null,
    target: null,
    /**
     * Contructor of cc.LoaderScene
     * @returns {boolean}
     */
    init: function () {
        // this賦值給self,後面不用 .bind(this)來訪問成員方法
        var self = this;

        //logo
        var logoWidth = 160;
        var logoHeight = 200;

        // bg  創建顏色層
        var bgLayer = self._bgLayer = new cc.LayerColor(cc.color(32, 32, 32, 255));
        // 添加到場景
        self.addChild(bgLayer, 0);

        //image move to CCSceneFile.js
        var fontSize = 24,
            lblHeight = -logoHeight / 2 + 100; // 默認正中間
        cc._loaderImage = null;
        if (cc._loaderImage) {
            //loading logo 
            // 加載logo
            cc.loader.loadImg(cc._loaderImage, {
                // 不跨域
                isCrossOrigin: false
            }, function (err, img) {
                logoWidth = img.width;
                logoHeight = img.height;
                // 顯示logo
                self._initStage(img, cc.visibleRect.center);
            });
            fontSize = 14;
            // 有logo的時候,logo往下 10像素
            lblHeight = -logoHeight / 2 - 10;
        }
        //loading percent
        var label = self._label = new cc.LabelTTF("Loading... 0%", "Arial", fontSize);
        // 設置座標
        label.setPosition(cc.pAdd(cc.visibleRect.center, cc.p(0, lblHeight)));
        label.setColor(cc.color(180, 180, 180));
        bgLayer.addChild(this._label, 10);
        return true;
    },

    _initStage: function (img, centerPos) {
        var self = this;
        // 創建紋理
        var texture2d = self._texture2d = new cc.Texture2D();
        texture2d.initWithElement(img);
        texture2d.handleLoadedTexture();
        var logo = self._logo = new cc.Sprite(texture2d);
        // 設置縮放
        logo.setScale(cc.contentScaleFactor());
        logo.x = centerPos.x;
        logo.y = centerPos.y;
        self._bgLayer.addChild(logo, 10);
    },
    /**
     * custom onEnter
     */
    onEnter: function () {
        var self = this;
        cc.Node.prototype.onEnter.call(self);
        // 0.3秒後執行 _startLoading  這邊是循環定時器
        self.schedule(self._startLoading, 0.3);
    },
    /**
     * custom onExit
     */
    onExit: function () {
        cc.Node.prototype.onExit.call(this);
        var tmpStr = "Loading... 0%";
        this._label.setString(tmpStr);
    },

    /**
     * init with resources
     * @param {Array} resources
     * @param {Function|String} cb
     * @param {Object} target
     */
    initWithResources: function (resources, cb, target) {
        if (cc.isString(resources))
            resources = [resources];
        this.resources = resources || [];
        this.cb = cb;
        this.target = target;
    },

    _startLoading: function () {
        var self = this;
        // 取消定時器
        self.unschedule(self._startLoading);
        var res = self.resources;
        // 加載資源
        cc.loader.load(res,
            // 每個加載後的回調
            function (result, count, loadedCount) {
                var percent = (loadedCount / count * 100) | 0;
                percent = Math.min(percent, 100);
                self._label.setString("Loading... " + percent + "%");
            },
            function () {
                if (self.cb)
                    self.cb.call(self.target);
            });
    },

    _updateTransform: function () {
        this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty);
        this._bgLayer._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty);
        this._label._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty);
        this._logo && this._logo._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty);
    }
});
/**
 * <p>cc.LoaderScene.preload can present a loaderScene with download progress.</p>
 * <p>when all the resource are downloaded it will invoke call function</p>
 * @param resources 需要加載的資源
 * @param cb 資源全部加載後的回調
 * @param target cb函數的指向
 * @returns {cc.LoaderScene|*}
 * @example
 * //Example
 * cc.LoaderScene.preload(g_resources, function () {
        cc.director.runScene(new HelloWorldScene());
    }, this);
 */
cc.LoaderScene.preload = function (resources, cb, target) {
    var _cc = cc;
    if (!_cc.loaderScene) {
        // 實例化LoaderScene
        _cc.loaderScene = new cc.LoaderScene();
        // 初始化,顯示logo等信息
        _cc.loaderScene.init();
        // 註冊監聽工程文件修改
        cc.eventManager.addCustomListener(cc.Director.EVENT_PROJECTION_CHANGED, function () {
            _cc.loaderScene._updateTransform();
        });
    }

    // 保存要加載的資源,資源全部加載完成後的回調
    _cc.loaderScene.initWithResources(resources, cb, target);
    // 運行當前場景
    cc.director.runScene(_cc.loaderScene);
    return _cc.loaderScene;
};

看下src/myApp.js的源碼

// 自己的層
var MyLayer = cc.Layer.extend({
    // 文本控件聲明
    helloLabel: null,
    // 精靈控件聲明
    sprite: null,

    init: function () {

        //////////////////////////////
        // 1. super init first
        this._super();

        /////////////////////////////
        // 2. add a menu item with "X" image, which is clicked to quit the program
        //    you may modify it.
        // ask director the window size
        // 獲取窗口大大
        var size = cc.director.getWinSize();

        // add a "close" icon to exit the progress. it's an autorelease object
        // 創建菜單選項
        var closeItem = new cc.MenuItemImage(
            s_CloseNormal,
            s_CloseSelected,
            function () {
                cc.log("close");
            }, this);
        // 設置錨點
        closeItem.setAnchorPoint(0.5, 0.5);
        // 創建菜單
        var menu = new cc.Menu(closeItem);
        menu.setPosition(0, 0);
        // 添加到層
        this.addChild(menu, 1);
        closeItem.setPosition(size.width - 20, 20);

        /////////////////////////////
        // 3. add your codes below...
        // add a label shows "Hello World"
        // create and initialize a label
        // 創建文本控件
        this.helloLabel = new cc.LabelTTF("Hello World", "Impact", 38);
        // position the label on the center of the screen
        this.helloLabel.setPosition(size.width / 2, size.height - 40);
        // add the label as a child to this layer
        this.addChild(this.helloLabel, 5);

        // add "Helloworld" splash screen"
        // 創建精靈
        this.sprite = new cc.Sprite(s_HelloWorld);
        this.sprite.setAnchorPoint(0.5, 0.5);
        this.sprite.setPosition(size.width / 2, size.height / 2);
        this.sprite.setScale(size.height / this.sprite.getContentSize().height);
        this.addChild(this.sprite, 0);
    }
});

// 自己的場景
var MyScene = cc.Scene.extend({
    // 運行場景後,下一幀執行該函數
    onEnter: function () {
        this._super();
        // 創建一個層
        var layer = new MyLayer();
        // 添加到場景上
        this.addChild(layer);
        // 運行層的init方法
        layer.init();
    }
});

做個總結:
1、入口爲index.html,裏面加載了CCBoot.js和main.js
2、main.js重寫了CCBoot.js裏面的cc.game.onStart方法,並執行cc.game.run(),然後執行onStart方法(原因見後面教程
3、onStart方法運行了LoaderScene場景並加載遊戲資源
4、加載成功後,運行自己的場景myScene

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章