Cocos Creator_官方案例解析_04_scripting

本文详细解析了Cocos Creator中的对象池(cc.NodePool)和资源管理,包括对象池的创建、获取、返回及清除,以及在游戏场景中的应用,强调了安全使用对象池的重要性,同时介绍了资产加载和网络相关的API。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

05_scripting/01_player_control
01_player_control
NodeArray(节点数组)

   properties: {
        nodeList: {
            default: [],
            type: [cc.Node] 声明数组对象:
        }
    },
    // use this for initialization
    onLoad: function () {
        var self = this;
        this.inervalId = setInterval(function () { //计时器
            self.toggleNodesVisibility();
        }, 1000);
    },
    onDestroy: function () {
        clearInterval(this.inervalId);
    },
    toggleNodesVisibility: function() {
        console.log('toggle visibility');
        for (var i = 0; i < this.nodeList.length; ++i) {
            this.nodeList[i].active = !this.nodeList[i].active;
        }
    }

NonSerialized(非序列化)
在这里插入图片描述
对象添加文本对象可以实现赋值操作。

ReferenceType(引用类型)

this.myComponent.getPower().toString();
myComponent 为当前脚本下的声明对象,getPower是myComponent下的挂载脚本,toString是getPower脚本中的方法,这样的掉用可以获取(引用)到其他脚本的数据。

ValueType(值类型)

 properties: {
        // number
        myNumber: {
            default: 0,
            type: cc.Integer
        },
        // string
        myString: {
            default: 'default text',
        },
        myVec2: {
            default: cc.Vec2.ZERO,
        },
        myColor: {
            default: cc.Color.WHITE,
        },
        myOtherNumber: 0,
        myOtherString: 'no type definition',
        myOtherVec2: cc.Vec2.ONE,
        myOtherColor: cc.Color.BLACK
    },

02_prefab
InstantiatePrefab(预制体的创建)

声明:
 properties: {
        prefab: {
            default: null,
            type: cc.Prefab
        },
    },
创建:
        var monster = cc.instantiate(this.prefab);
        monster.parent = this.root;
        //this.canvas.node.addChild(monster);
        monster.position = this.getRandomPosition();

03_events
EventInMask(遮罩)
遮罩的顺序和Canvas下的排列顺序相关联。排序越往上,遮罩时越下层。

MousePropagation(鼠标事件)

鼠标事件的监听大致可分为以下三种情况
cc.Node.EventType.MOUSE_DOWN (点击)
cc.Node.EventType.MOUSE_MOVE(移动)
cc.Node.EventType.MOUSE_LEAVE(离开,结束)
cc.Node.EventType.MOUSE_ENTER()

SimpleEvent(基本事件)

cc.Node.EventType.MOUSE_WHEEL(滚轮监听)

TouchPropagation(触摸事件)

cc.Node.EventType.TOUCH_START (进入)
cc.Node.EventType.TOUCH_MOVE(移动)
cc.Node.EventType.TOUCH_END(退出)

04_scheduler
scheduler(计时器)

his.scheduleOnce(function(){
    /*****1秒后执行1次*****/
}.bind(this),1);
this.schedule(function(){
    /*****每隔2秒执行1次*****/
}.bind(this),2);
this.schedule(function(){
    /*****1秒后开始执行,间隔0.1秒,共执行9次*****/
}.bind(this),0.1,8,1);
this.unscheduleAllCallbacks(this); //停止this指向的组件的所有计时器

05_cross_reference
CircleReference(循环引用)

      this.node.on(cc.Node.EventType.TOUCH_END, function () {
            var newnode = cc.instantiate(this.prefab);
            var parent = this.node.parent;
            this.node.parent = null;
            newnode.parent = parent;
        }, this);

CrossReference(交叉引用)

    properties: () => ({
        refToFoo: require('Foo'), //规定了应用对象的名称
        test: cc.Node
    }),
    // use this for initialization
    onLoad: function () {
        var tip = this.node.children[0].getComponent(cc.Label);
        tip.string = this.name + ' has reference to ' + this.refToFoo.name;
        console.log("引用对象"+this.test.name);         // Foo
        console.log("引用对象"+this.refToFoo.name); // Foo<Foo>
    }

06_life_cycle*
life_cycle(函数生命周期)

  console.log("Pos: " + this.node.getPosition().x + ", " + this.node.getPosition().y);
        this.node.runAction(cc.sequence(cc.moveBy(2, 200, 0)//执行时间,一定距离, cc.callFunc(function () {
            console.log("Pos: " + this.node.x + ", " + this.node.y); //顺序执行动作,创建的动作将按顺序依次运行。
            this.node.destroy();
        }, this)));

07_asset_loading
AssetLoading(资产加载)

const i18n = require('i18n');
cc.Class({
    extends: cc.Component,
    properties: {
        showWindow: cc.Node,
        loadAnimTestPrefab: cc.Prefab,
        loadTips: cc.Label,
        loadList: {
            default: [],
            type: cc.Node
        }
    },
    // use this for initialization
    onLoad: function () {
        // cur load Target
        this._curType = "";
        this._lastType = "";
        this._curRes = null;
        this._btnLabel = null;
        this._audioSource = null;
        this._isLoading = false;
        // add load res url
        this._urls = {
            // Raw Asset
            Audio: "test assets/audio",
            Txt: "test assets/text",
            Texture: "test assets/PurpleMonster",
            Font: "test assets/font",
            // Raw Asset, use raw url
            Plist: cc.url.raw("resources/test assets/atom.plist"),
            // Asset
            SpriteFrame: "test assets/image",
            Prefab: "test assets/prefab",
            Animation: "test assets/sprite-anim",
            Scene: "test assets/scene",
            Spine: "spineboy/spineboy",
            CORS: "http://tools.itharbors.com/res/logo.png",
        };
        // registered event
        this._onRegisteredEvent();
    },
    _onRegisteredEvent: function () {
        for (var i = 0; i < this.loadList.length; ++i) {
            this.loadList[i].on(cc.Node.EventType.TOUCH_END, this._onClick.bind(this));
        }
    },
    _onClick: function (event) {
        if (this._isLoading) {
            return;
        }
        this._onClear();      
        this._curType = event.target.name.split('_')[1];
        console.log("事件名称"+  this._curType );
        if (this._lastType !== "" && this._curType === this._lastType) {
            this._onShowResClick(event);
            return;
        }
        if (this._btnLabel) {
            this._btnLabel.textKey = i18n.t("cases/05_scripting/07_asset_loading/AssetLoading.js.1") + this._lastType;
        }
        this._lastType = this._curType;
        this._btnLabel = event.target.getChildByName("Label").getComponent("cc.Label");
        this.loadTips.textKey = this._curType + " Loading....";
        this._isLoading = true;
        this._load();
    },
    _load: function () {
        var url = this._urls[this._curType];
        var loadCallBack = this._loadCallBack.bind(this);
        switch (this._curType) {
            case 'SpriteFrame':
                // specify the type to load sub asset from texture's url
                cc.loader.loadRes(url, cc.SpriteFrame, loadCallBack);
                break;
            case 'Spine':
                // specify the type to avoid the duplicated name from spine atlas
                cc.loader.loadRes(url, sp.SkeletonData, loadCallBack);
                break;
            case 'Font':
                cc.loader.loadRes(url, cc.Font, loadCallBack);
                break;
            case 'Animation':
            case 'Prefab':
            case 'Scene':
            case 'Texture':
            case 'Txt':
            case 'Audio':
                cc.loader.loadRes(url, loadCallBack);
                break;
            case 'CORS':
                cc.loader.load(url, loadCallBack);
                this.loadTips.textKey = "CORS image should report texImage2D error under WebGL and works ok under Canvas"
                break;
            default:
                cc.loader.load(url, loadCallBack);
                break;
        }
    },
    _loadCallBack: function (err, res) {
        this._isLoading = false;
        if (err) {
            cc.log('Error url [' + err + ']');
            return;
        }
        this._curRes = res;
        if (this._curType === "Audio") {
            this._btnLabel.textKey = i18n.t("cases/05_scripting/07_asset_loading/AssetLoading.js.2");
        }
        else {
            this._btnLabel.textKey = i18n.t("cases/05_scripting/07_asset_loading/AssetLoading.js.3");
        }
        this._btnLabel.textKey += this._curType;
        this.loadTips.textKey = this._curType + " Loaded Successfully!";
    },
    _onClear: function () {
        this.showWindow.removeAllChildren(true);
        if (this._audioSource && this._audioSource instanceof cc.AudioSource) {
            this._audioSource.stop();
        }
    },
    _onShowResClick: function (event) {
        if (this._curType === "Scene") {
            cc.director.runScene(this._curRes.scene);
            cc.loader.releaseAsset(this._curRes);
            this._curRes = null;
            return;
        }
        this._createNode(this._curType, this._curRes);
    },
    _createNode: function (type, res) {
        this.loadTips.textKey = "";
        var node = new cc.Node("New " + type);
        node.setPosition(0, 0);
        var component = null;
        switch (this._curType) {
            case "SpriteFrame":
                component = node.addComponent(cc.Sprite);
                component.spriteFrame = res;
                break;
            case "Texture":
            case "CORS":
                component = node.addComponent(cc.Sprite);
                component.spriteFrame = new cc.SpriteFrame(res);
                break;
            case "Audio":
                component = node.addComponent(cc.AudioSource);
                component.clip = res;
                component.play();
                this._audioSource = component;
                this.loadTips.textKey = i18n.t("cases/05_scripting/07_asset_loading/AssetLoading.js.4");
                break;
            case "Txt":
                component = node.addComponent(cc.Label);
                component.lineHeight = 40;
                component.string = res;
                break;
            case "Font":
                component = node.addComponent(cc.Label);
                component.font = res;
                component.lineHeight = 40;
                component.string = "This is BitmapFont!";
                break;
            case "Plist":
                component = node.addComponent(cc.ParticleSystem);
                component.file = this._urls.Plist;
                component.resetSystem();
                break;
            case "Prefab":
                var prefab = cc.instantiate(res);
                prefab.parent = node;
                prefab.setPosition(0, 0);
                break;
            case "Animation":
                var loadAnim = cc.instantiate(this.loadAnimTestPrefab);
                loadAnim.parent = node;
                loadAnim.setPosition(0, 0);
                var AanimCtrl = loadAnim.getComponent(cc.Animation);
                AanimCtrl.addClip(res);
                AanimCtrl.play(res.name);
                break;
            case "Spine":
                component = node.addComponent(sp.Skeleton);
                component.skeletonData = res;
                component.animation = "walk";
                node.y = -248;
                break;
        }
        this.showWindow.addChild(node);
    }
});

LoadResDir

cc.Class({
    extends: cc.Component,
    properties: {
        btnClearAll: cc.Node, // 清空节点
        label: cc.Prefab,     // 文字预制体
        scrollView: cc.ScrollView // 视图插件
    },
    _init: function () {
        this._assets = [];
        this._hasLoading = false;
        this.scrollView.content.height = 0;
        this.btnClearAll.active = false;
    },
    onLoad: function () {
        this._init();
    },
    _createLabel: function (text) {
        var node = cc.instantiate(this.label);
        var label = node.getComponent(cc.Label);
        label.textKey = text;
        this.scrollView.content.addChild(node);
    },
    _clear: function () {
        this.scrollView.content.removeAllChildren(true);
        for (var i = 0; i < this._assets.length; ++i) {
            var asset = this._assets[i];
            // 目前载入 plist 后的 Object 资源没有包含 _uuid 所以无法 release(PS:1.5 版本会加 _uuid)
            // 暂时过滤 Object 并且没有 _uuid 类型的资源
            if (typeof asset === 'object' && !asset._uuid) {
                continue;
            }
            cc.loader.release(this._assets[i]);
        }
    },
    onClearAll: function () {
        this.scrollView.content.height = 0;
        this.btnClearAll.active = false;
        this._clear();
    },
    onLoadAll: function () {
        if (this._hasLoading) { return; }
        this._hasLoading = true;
        this._clear();
        this._createLabel("Load All Assets");
        this.scrollView.scrollToTop();
        cc.loader.loadResDir("test assets", (err, assets) => {
            if (!this.isValid) {
                return;
            }
            this._assets = assets;
            var text = "";
            for (var i = 0; i < assets.length; ++i) {
                if (typeof assets[i] === 'string') {
                    text = assets[i]
                }
                else {
                    text = assets[i].url || assets[i]._name || assets[i];
                }
                if (typeof text !== 'string' ) {
                    continue;
                }
                this._createLabel(text);
            }
            this._hasLoading = false;
            this.btnClearAll.active = true;
        });
    },
    onLoadSpriteFrameAll: function () {
        if (this._hasLoading) { return; }
        this._hasLoading = true;
        this._clear();
        this._createLabel("Load All Sprite Frame");
        this.scrollView.scrollToTop();
        cc.loader.loadResDir("test assets", cc.SpriteFrame, (err, assets) => {
            if (!this.isValid) {
                return;
            }
            this._assets = assets;
            var text = "";
            for (var i = 0; i < assets.length; ++i) {
                if (typeof assets[i] === 'string' ) {
                    text = assets[i]
                }
                else {
                    text = assets[i].url || assets[i]._name || assets[i];
                }
                this._createLabel(text);
            }
            this._hasLoading = false;
            this.btnClearAll.active = true;
        });
    }
});

LoadRes

	 onLoad: function () {
	        this._url = ["test assets/atlas", "test assets/prefab"];
	    },
      loadPrefab: function () {
        var url = this._url[1];
        this._releaseResource(url, cc.Prefab);
        cc.loader.loadRes(url, cc.Prefab, (err, prefab) => {
            this._removeAllChildren(); 
            cc.loader.setAutoRelease(prefab, true);
            var node = cc.instantiate(prefab);
            this.content.addChild(node);
            node.position = cc.v2(0, 0); // 创建对象位置赋值
        });
    },
    _removeAllChildren: function () {
        this.content.removeAllChildren(true);  //清除其他子物体
    },
    _releaseResource: function (url, type) {
        this._removeAllChildren();
        var res = cc.loader.getRes(url, type);
        var all = cc.loader.getDependsRecursively(res);
        cc.loader.release(all); //通过资源对象自身来释放资源
    }

08_module
load_module(加载模块)

使用 cc.instantiate创建预制体对象,然后赋值文字信息,图片信息进行加载模式。

09_singleton
Singleton(单例模式)

10_loadingBar
loadingBar(进度条)

cc.Class({
    extends: cc.Component,
    properties: {
        progressBar: {
            default: null,
            type: cc.ProgressBar
        },
        progressTips: {
            default: null,
            type: cc.Label
        },
        laodBg: {
            default: null,
            type: cc.Node
        }
    },
    onLoad: function () {
        this._urls = [
            cc.url.raw("resources/audio/ding.wav"),
            cc.url.raw("resources/audio/cheering.wav"),
            cc.url.raw("resources/audio/music_logo.mp3"),
            cc.url.raw("resources/test assets/audio.mp3"),
            cc.url.raw("resources/loadingBar/font.png"),
            cc.url.raw("resources/loadingBar/mikado_outline_shadow.png"),
            cc.url.raw("resources/loadingBar/enligsh-chinese.png")
        ];
        this.resource = null;
        this.progressBar.progress = 0;
        this._clearAll();
        this.progressTips.textKey = i18n.t("cases/05_scripting/10_loadingBar/LoadingBarCtrl.js.3");
        this.node.on(cc.Node.EventType.TOUCH_START, function () {
            if (this.resource) { return; }
            cc.loader.load(this._urls, this._progressCallback.bind(this), this._completeCallback.bind(this)); //事件触发
        }, this);
    },
    _clearAll: function () {
        for (var i = 0; i < this._urls.length; ++i) {
            var url = this._urls[i];
            cc.loader.release(url);
        }
    },
    _progressCallback: function (completedCount, totalCount, res) {
        this.progress = completedCount / totalCount;
        this.resource = res; //开启循环
        this.completedCount = completedCount;
        this.totalCount = totalCount;
    },
    _completeCallback: function (error, res) {

    },
    update: function (dt) {
        if (!this.resource) {
            return;
        }
        var progress = this.progressBar.progress;
        if (progress >= 1) {
            this.progressTips.textKey = i18n.t("cases/05_scripting/10_loadingBar/LoadingBarCtrl.js.1");
            this.laodBg.active = false;
            this.progressBar.node.active = false;
            this.enabled = false;
            return;
        }
        if (progress < this.progress) {
            progress += dt;
        }
        this.progressBar.progress = progress;
        this.progressTips.textKey = i18n.t("cases/05_scripting/10_loadingBar/LoadingBarCtrl.js.2")+ this.resource.id + " (" + this.completedCount + "/" + this.totalCount + ")";
    }
});

11_network
downloader(下载器)

cc.Class({
    extends: cc.Component,
    properties: {
        label: cc.Label,
        sprite: cc.Sprite,
        imgUrl: "http://www.cocos.com/wp-content/themes/cocos/img/download1.png",
        txtUrl: "http://api.lololyrics.com/0.5/getLyric?artist=John%20Lennon&track=Imagine",
        _downloader: null,
        _imgTask: null,
        _txtTask: null,
        _storagePath: "",
        _inited: false
    },
    // use this for initialization
    onLoad () {
        if (!CC_JSB) {
            this.label.string = 'Downloader is a NATIVE ONLY feature.';
            return;
        }
        this._downloader = new jsb.Downloader();
        this._downloader.setOnFileTaskSuccess(this.onSucceed.bind(this));
        this._downloader.setOnTaskProgress(this.onProgress.bind(this));
        this._downloader.setOnTaskError(this.onError.bind(this));
        this._storagePath = jsb.fileUtils.getWritablePath() + '/example-cases/downloader/';
        this._inited = jsb.fileUtils.createDirectory(this._storagePath);
        if (!this._inited) {
            this.label.string = 'Failed to create storage path, downloader won\'t work correctly';
        }
    },
    onSucceed (task) {
        var atlasRelated = false;
        switch (task.requestURL) {
        case this.imgUrl:
            var self = this;
            cc.loader.load(task.storagePath, function (err, tex) {
                var spriteFrame = new cc.SpriteFrame(tex);
                self.sprite.spriteFrame = spriteFrame;
                self.sprite.node.active = true;
                self.label.node.active = false;
            });
            break;
        case this.txtUrl:
            var content = jsb.fileUtils.getStringFromFile(task.storagePath);
            this.sprite.node.active = false;
            this.label.node.active = true;
            this.label.string = content.substr(0, 350);
            break;
        }
    },
    onProgress (task, bytesReceived, totalBytesReceived, totalBytesExpected) {
    },
    onError (task, errorCode, errorCodeInternal, errorStr) {
        this.sprite.node.active = false;
        this.label.node.active = true;
        this.label.string = 'Failed to download file (' + task.requestURL + '): ' + errorStr + '(' + errorCode + ')';
    },
    downloadImg () {
        if (!this.imgUrl || !this._inited) {
            return;
        }
        this._imgTask = this._downloader.createDownloadFileTask(this.imgUrl, this._storagePath + 'download1.png');
    },
    downloadTxt () {
        if (!this.txtUrl || !this._inited) {
            return;
        }
        this._txtTask = this._downloader.createDownloadFileTask(this.txtUrl, this._storagePath + 'imagine.txt');
    }
});

network(网络)

const i18n = require('i18n');
cc.Class({
    extends: cc.Component,
    properties: {
        xhr: cc.Label,
        xhrAB: cc.Label,
        xhrTimeout: cc.Label,
        websocket: cc.Label,
        socketIO: cc.Label,
        xhrResp: cc.Label,
        xhrABResp: cc.Label,
        xhrTimeoutResp: cc.Label,
        websocketResp: cc.Label,
        socketIOResp: cc.Label
    },
    // use this for initialization
    onLoad: function () {
        this._wsiSendBinary = null;
        this.xhrResp.textKey = "cases/05_scripting/11_network/NetworkCtrl.js.1";
        this.xhrABResp.textKey = "cases/05_scripting/11_network/NetworkCtrl.js.2";
        this.xhrTimeoutResp.textKey = "cases/05_scripting/11_network/NetworkCtrl.js.2";
        this.websocketResp.textKey = "cases/05_scripting/11_network/NetworkCtrl.js.3";
        this.socketIOResp.textKey = "cases/05_scripting/11_network/NetworkCtrl.js.4";
        this.sendXHR();
        this.sendXHRAB();
        this.sendXHRTimeout();
        this.prepareWebSocket();
        this.sendSocketIO();
    },
    sendXHR: function () {
        var xhr = cc.loader.getXMLHttpRequest();
        this.streamXHREventsToLabel(xhr, this.xhr, this.xhrResp, 'GET');
        xhr.open("GET", "https://httpbin.org/get?show_env=1", true);
        if (cc.sys.isNative) {
            xhr.setRequestHeader("Accept-Encoding","gzip,deflate");
        }
        // note: In Internet Explorer, the timeout property may be set only after calling the open()
        // method and before calling the send() method.
        xhr.timeout = 5000;// 5 seconds for timeout
        xhr.send();
    },
    sendXHRAB: function () {
        var xhr = cc.loader.getXMLHttpRequest();
        this.streamXHREventsToLabel(xhr, this.xhrAB, this.xhrABResp, "POST");
        xhr.open("POST", "https://httpbin.org/post");
        //set Content-type "text/plain" to post ArrayBuffer or ArrayBufferView
        xhr.setRequestHeader("Content-Type","text/plain");
        // Uint8Array is an ArrayBufferView
        xhr.send(new Uint8Array([1,2,3,4,5]));
    },
    sendXHRTimeout: function () {
        var xhr = new XMLHttpRequest();
        this.streamXHREventsToLabel(xhr, this.xhrTimeout, this.xhrTimeoutResp, 'GET');
        xhr.open("GET", "https://192.168.22.222", true);
        // note: In Internet Explorer, the timeout property may be set only after calling the open()
        // method and before calling the send() method.
        xhr.timeout = 5000;// 5 seconds for timeout
        xhr.send();
    },
    prepareWebSocket: function () {
        var self = this;
        var websocketLabel = this.websocket;
        var respLabel = this.websocketResp;
        this._wsiSendBinary = new WebSocket("ws://echo.websocket.org");
        this._wsiSendBinary.binaryType = "arraybuffer";
        this._wsiSendBinary.onopen = function(evt) {
            websocketLabel.textKey = "cases/05_scripting/11_network/NetworkCtrl.js.5";
        };
        this._wsiSendBinary.onmessage = function(evt) {
            var binary = new Uint16Array(evt.data);
            var binaryStr = 'response bin msg: ';
            var str = '';
            for (var i = 0; i < binary.length; i++) {
                if (binary[i] === 0)
                {
                    str += "\'\\0\'";
                }
                else
                {
                    var hexChar = '0x' + binary[i].toString('16').toUpperCase();
                    str += String.fromCharCode(hexChar);
                }
            }
            binaryStr += str;
            respLabel.string = binaryStr;
            websocketLabel.textKey = "cases/05_scripting/11_network/NetworkCtrl.js.6";
        };
        this._wsiSendBinary.onerror = function(evt) {
            websocketLabel.textKey = "cases/05_scripting/11_network/NetworkCtrl.js.7";
        };
        this._wsiSendBinary.onclose = function(evt) {
            websocketLabel.textKey = "cases/05_scripting/11_network/NetworkCtrl.js.8";
            // After close, it's no longer possible to use it again, 
            // if you want to send another request, you need to create a new websocket instance
            self._wsiSendBinary = null;
        };
        this.scheduleOnce(this.sendWebSocketBinary, 1);
    },
    sendWebSocketBinary: function(sender)
    {
        if (!this._wsiSendBinary) { return; }
        if (this._wsiSendBinary.readyState === WebSocket.OPEN)
        {
            this.websocket.textKey = "cases/05_scripting/11_network/NetworkCtrl.js.9";
            var buf = "Hello WebSocket中文,\0 I'm\0 a\0 binary\0 message\0.";
            var arrData = new Uint16Array(buf.length);
            for (var i = 0; i < buf.length; i++) {
                arrData[i] = buf.charCodeAt(i);
            }
            this._wsiSendBinary.send(arrData.buffer);
        }
        else
        {
            var warningStr = "send binary websocket instance wasn't ready...";
            this.websocket.string = i18n.t("cases/05_scripting/11_network/NetworkCtrl.js.10") + warningStr;
            this.scheduleOnce(function () {
                this.sendWebSocketBinary();
            }, 1);
        }
    },
    // Socket IO callbacks for testing
    testevent: function(data) {
        if (!this.socketIO) { return; }
        var msg = this.tag + " says 'testevent' with data: " + data;
        this.socketIO.string = i18n.t("cases/05_scripting/11_network/NetworkCtrl.js.11") + msg;
    },
    message: function(data) {
        if (!this.socketIO) { return; }
        var msg = this.tag + " received message: " + data;
        this.socketIOResp.string = msg;
    },
    disconnection: function() {
        if (!this.socketIO) { return; }
        var msg = this.tag + " disconnected!";
        this.socketIO.string = i18n.t("cases/05_scripting/11_network/NetworkCtrl.js.12") + msg;
    },
    sendSocketIO: function () {
        var self = this;
        if (typeof io === 'undefined') {
            cc.error('You should import the socket.io.js as a plugin!');
            return;
        }
        //create a client by using this static method, url does not need to contain the protocol
        var sioclient = io.connect("ws://tools.itharbors.com:4000", {"force new connection" : true});
        this._sioClient = sioclient;
        //if you need to track multiple sockets it is best to store them with tags in your own array for now
        this.tag = sioclient.tag = "Test Client";
        //register event callbacks
        //this is an example of a handler declared inline
        sioclient.on("connect", function() {
            if (!self.socketIO) { return; }
            var msg = sioclient.tag + " Connected!";
            self.socketIO.string = i18n.t("cases/05_scripting/11_network/NetworkCtrl.js.13") + msg;
            // Send message after connection
            self._sioClient.send("Hello Socket.IO!");
        });
        //example of a handler that is shared between multiple clients
        sioclient.on("message", this.message.bind(this));
        sioclient.on("echotest", function (data) {
            if (!self.socketIO) { return; }
            cc.log("echotest 'on' callback fired!");
            var msg = self.tag + " says 'echotest' with data: " + data;
            self.socketIO.string = i18n.t("cases/05_scripting/11_network/NetworkCtrl.js.14") + msg;
        });
        sioclient.on("testevent", this.testevent.bind(this));
        sioclient.on("disconnect", this.disconnection.bind(this));
    },
    streamXHREventsToLabel: function ( xhr, eventLabel, label, method, responseHandler ) {
        var handler = responseHandler || function (response) {
            return method + " Response (30 chars): " + response.substring(0, 30) + "...";
        };
        var eventLabelOrigin = eventLabel.string;
        // Simple events
        ['loadstart', 'abort', 'error', 'load', 'loadend', 'timeout'].forEach(function (eventname) {
            xhr["on" + eventname] = function () {
                eventLabel.string = eventLabelOrigin + "\nEvent : " + eventname;
                if (eventname === 'timeout') {
                    label.string = '(timeout)';
                }
            };
        });
        // Special event 
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 300)) {
                label.string = handler(xhr.responseText);
            }
        };
    }
});

12_pool
nodePool(对象池)
对象池就是一组可回收的节点对象,我们通过创建 cc.NodePool 的实例来初始化一种节点的对象池。通常当我们有多个 prefab 需要实例化时,应该为每个 prefab 创建一个 cc.NodePool 实例。 当我们需要创建节点时,向对象池申请一个节点,如果对象池里有空闲的可用节点,就会把节点返回给用户,用户通过 node.addChild 将这个新节点加入到场景节点树中。
当我们需要销毁节点时,调用对象池实例的 put(node) 方法,传入需要销毁的节点实例,对象池会自动完成把节点从场景节点树中移除的操作,然后返回给对象池。这样就实现了少数节点的循环利用。 假如玩家在一关中要杀死 n 个敌人,但同时出现的敌人不超过 m 个,那我们就只需要生成 m个节点大小的对象池,然后循环使用就可以了。
关于 cc.NodePool 的详细 API 说明,请参考 添加链接描述cc.NodePool API 文档。

对象池使用的工作流程:
1准备好Prefab
2初始化对象池:在场景加载的初始化脚本中,我们可以将需要数量的节点创建出来,并放进对象池:

properties: {
    enemyPrefab: cc.Prefab
},
onLoad: function () {
    this.enemyPool = new cc.NodePool();
    let initCount = 5;
    for (let i = 0; i < initCount; ++i) {
        let enemy = cc.instantiate(this.enemyPrefab); // 创建节点
        this.enemyPool.put(enemy); // 通过 putInPool 接口放入对象池
    }

3从对象池请求对象

createEnemy: function (parentNode) {
    let enemy = null;
    if (this.enemyPool.size() > 0) { // 通过 size 接口判断对象池中是否有空闲的对象
        enemy = this.enemyPool.get();
    } else { // 如果没有空闲对象,也就是对象池中备用对象不够时,我们就用 cc.instantiate 重新创建
        enemy = cc.instantiate(this.enemyPrefab);
    }
    enemy.parent = parentNode; // 将生成的敌人加入节点树
    enemy.getComponent('Enemy').init(); //接下来就可以调用 enemy 身上的脚本进行初始化
}

安全使用对象池的要点就是在 get 获取对象之前,永远都要先用 size 来判断是否有可用的对象,如果没有就使用正常创建节点的方法,虽然会消耗一些运行时性能,但总比游戏崩溃要好!另一个选择是直接调用 get,如果对象池里没有可用的节点,会返回 null,在这一步进行判断也可以。
4将对象返回对象池
当我们杀死敌人时,需要将敌人节点退还给对象池,以备之后继续循环利用,我们用这样的方法:

onEnemyKilled: function (enemy) {
    // enemy 应该是一个 cc.Node
    this.enemyPool.put(enemy); // 和初始化时的方法一样,将节点放进对象池,这个方法会同时调用节点的 removeFromParent

5清除对象池
如果对象池中的节点不再被需要,我们可以手动清空对象池,销毁其中缓存的所有节点:

myPool.clear(); // 调用这个方法就可以清空对象池

myPool.clear(); // 调用这个方法就可以清空对象池
当对象池实例不再被任何地方引用时,引擎的垃圾回收系统会自动对对象池中的节点进行销毁和回收。但这个过程的时间点不可控,另外如果其中的节点有被其他地方所引用,也可能会导致内存泄露,所以最好在切换场景或其他不再需要对象池的时候手动调用 clear 方法来清空缓存节点。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值