天天看點

Cocos Creator 通路節點群組件

一、獲得元件所在的節點

獲得元件所在的節點很簡單,隻要在元件方法裡通路 this.node 變量:

    start: function () {

        var node = this.node;

        node.x = 100;

    }

二、獲得其它元件

你會經常需要獲得同一個節點上的其它元件,這就要用到 getComponent 這個 API,它會幫你查找你要的元件。

    start: function () {

        var label = this.getComponent(cc.Label);

        var text = this.name + ' started';

        // Change the text in Label Component

        label.string = text;

    }

你也可以為 getComponent 傳入一個類名。對使用者定義的元件而言,類名就是腳本的檔案名,并且區分大小寫。例如 "SinRotate.js" 裡聲明的元件,類名就是 "SinRotate"。

    var label = this.getComponent("cc.Label");

在節點上也有一個 getComponent 方法,它們的作用是一樣的:

    start: function () {

        cc.log( this.node.getComponent(cc.Label) === this.getComponent(cc.Label) );  // true

    }

如果在節點上找不到你要的元件,getComponent 将傳回 null,如果你嘗試通路 null 的值,将會在運作時抛出 "TypeError" 這個錯誤。是以如果你不确定元件是否存在,請記得判斷一下:

    start: function () {

        var label = this.getComponent(cc.Label);

        if (label) {

            label.string = "Hello";

        }

        else {

            cc.error("Something wrong?");

        }

    }

三、獲得其它節點及其元件

僅僅能通路節點自己的元件通常是不夠的,腳本通常還需要進行多個節點之間的互動。例如,一門自動瞄準玩家的大炮,就需要不斷擷取玩家的最新位置。Cocos Creator 提供了一些不同的方法來獲得其它節點或元件。

利用屬性檢查器設定節點

最直接的方式就是在 屬性檢查器 中設定你需要的對象。以節點為例,這隻需要在腳本中聲明一個 type 為 cc.Node 的屬性:

// Cannon.js

cc.Class({

    extends: cc.Component,

    properties: {

        // 聲明 player 屬性

        player: {

            default: null,

            type: cc.Node

        }

    }

});

這段代碼在 properties 裡面聲明了一個 player 屬性,預設值為 null,并且指定它的對象類型為 cc.Node。這就相當于在其它語言裡聲明了 public cc.Node player = null;。腳本編譯之後,這個元件在 屬性檢查器 中看起來是這樣的:

Cocos Creator 通路節點群組件

接着你就可以将層級管理器上的任意一個節點拖到這個 Player 控件:

Cocos Creator 通路節點群組件

這樣一來它的 player 屬性就會被設定成功,你可以直接在腳本裡通路 player:

// Cannon.js

var Player = require("Player");

cc.Class({

    extends: cc.Component,

    properties: {

        // 聲明 player 屬性

        player: {

            default: null,

            type: cc.Node

        }

    },

    start: function () {

        var playerComp = this.player.getComponent(Player);

        this.checkPlayer(playerComp);

    },

    // ...

});

四、利用屬性檢查器設定元件

在上面的例子中,如果你将屬性的 type 聲明為 Player 元件,當你拖動節點 "Player Node" 到 屬性檢查器,player 屬性就會被設定為這個節點裡面的 Player 元件。這樣你就不需要再自己調用 getComponent 啦。

// Cannon.js

var Player = require("Player");

cc.Class({

    extends: cc.Component,

    properties: {

        // 聲明 player 屬性,這次直接是元件類型

        player: {

            default: null,

            type: Player

        }

    },

    start: function () {

        var playerComp = this.player;

        this.checkPlayer(playerComp);

    },

    // ...

});

你還可以将屬性的預設值由 null 改為數組[],這樣你就能在 屬性檢查器 中同時設定多個對象。

不過如果需要在運作時動态擷取其它對象,還需要用到下面介紹的查找方法。

五、查找子節點

有時候,遊戲場景中會有很多個相同類型的對象,像是炮塔、敵人和特效,它們通常都有一個全局的腳本來統一管理。如果用 屬性檢查器 來一個一個将它們關聯到這個腳本上,那工作就會很繁瑣。為了更好地統一管理這些對象,我們可以把它們放到一個統一的父物體下,然後通過父物體來獲得所有的子物體:

// CannonManager.js

cc.Class({

    extends: cc.Component,

    start: function () {

        this.cannons = [];

        this.cannons = this.node.getChildren();

    }

});

這裡的 getChildren 是 cc.Node 原有的一個 API,可以獲得一個包含所有子節點的數組。

你還可以使用 getChildByName:

this.node.getChildByName("Cannon 01");

如果子節點的層次較深,你還可以使用 cc.find,cc.find 将根據傳入的路徑進行逐級查找:

cc.find("Cannon 01/Barrel/SFX", this.node);

六、全局名字查找

當 cc.find 隻傳入第一個參數時,将從場景根節點開始逐級查找:

this.backNode = cc.find("Canvas/Menu/Back");

通路已有變量裡的值

如果你已經在一個地方儲存了節點或元件的引用,你也可以直接通路它們,一般有兩種方式:

七、通過全局變量通路

你應當很謹慎地使用全局變量,當你要用全局變量時,應該很清楚自己在做什麼,我們并不推薦濫用全局變量,即使要用也最好保證全局變量隻讀。

讓我們試着定義一個全局對象 window.Global,這個對象裡面包含了 backNode 和 backLabel 兩個屬性。

// Globals.js, this file can have any name

window.Global = {//類似宏定義;

    backNode: null,

    backLabel: null,

};

由于所有腳本都強制聲明為 "use strict",是以定義全局變量時的 window. 不可省略。

接着你可以在合适的地方直接通路并初始化 Global:

// Back.js

cc.Class({

    extends: cc.Component,

    onLoad: function () {

        Global.backNode = this.node;

        Global.backLabel = this.getComponent(cc.Label);

    }

});

初始化後,你就能在任何地方通路到 Global 裡的值:

// AnyScript.js

cc.Class({

    extends: cc.Component,

// start 會在 onLoad 之後執行,是以這時 Global 已經初始化過了

    start: function () {

        var text = 'Back';

        Global.backLabel.string = text;

    }

});

通路全局變量時,如果變量未定義将會抛出異常。

添加全局變量時,請小心不要和系統已有的全局變量重名。

你需要小心確定全局變量使用之前都已初始化和指派。

八、通過子產品通路

如果你不想用全局變量,你可以使用 require 來實作腳本的跨檔案操作,讓我們看個示例:

// Global.js, now the filename matters

module.exports = {

    backNode: null,

    backLabel: null,

};

每個腳本都能用 require + 檔案名(不含路徑) 來擷取到對方 export 的對象。

// Back.js

// this feels more safe since you know where the object comes from

var Global = require("Global");

cc.Class({

    extends: cc.Component,

    onLoad: function () {

     Global.backNode = this.node;

        Global.backLabel = this.getComponent(cc.Label);

    }

});

// AnyScript.js

// this feels more safe since you know where the object comes from

var Global = require("Global");

cc.Class({

    extends: cc.Component,

    // start 會在 onLoad 之後執行,是以這時 Global 已經初始化過了

    start: function () {

        var text = "Back";

        Global.backLabel.string = text;

    }

});