Cocos Creator 踩坑記錄


1.動態添加的腳本,腳本事件不執行。

寫好了腳本XTimer,采用動態addComponent(Xtimer),但是腳本的start update都不執行。

代碼如下:

var node = new cc.Node('[XTimer]')
            //調用新建的node的addComponent函數,會返回一個sprite的對象
        node.addComponent(XTimer);

 

檢查發現一切正常,就連輸出添加后的alert("BBBBBBBBBBBBB:" + node.active + " " + ttt.enabled); 這兩個值都是ture。而且發現將XTimer拖動到場景物體上就正常,只有動態添加的不正常。

后來發現是未給node設置父節點的問題。但我想把node就在場景跟節點中,所以在節點后添加如下代碼。

var scene = cc.director.getScene();
        node.setParent(scene);

OK,正常運行了。

====================================

2.getChildByName獲取不到子物體。

今天發現getChildByName獲取不到層次2次以上的子物體。如

var life2 = this.obj.getChildByName("dao/boxlife2");

找了很多資料才知道:

2)查找子節點一般用this.node.getChildByName(),如果子節點的層次較深,你還可以使用 cc.find("Cannon 01/Barrel/SFX", this.node)。注意,當 cc.find 只傳入第一個參數時,將從場景根節點開始逐級查找,如:cc.find("Canvas/Menu/Back");
如上所述,getChildByName只能查找以及目錄。要查找路徑還得用:var life1 = cc.find("dao/boxlife1", this.obj);
OK,2問題解決。
 
3.函數回調不是注冊時的所在的對象。======================================
今天編寫觀察者模式,用於在UI上訂閱事件,然后在戰斗邏輯中觸發該事件。然而發現消息函數執行了,但卻並不是組成時的對象。
代碼如下圖:訂閱者
export default class ui_page_battle extends UIBaseWindow {
    public numid: string = "-1";
    public _AwakeImpl() {
        this.numid = GUtil.GetUUID();
        GUtil.BindOnClick(this.txtBtn, this.node, "txtBtnClick", "222");
        XObserverCore.RegisterNotification(ConstDefineNotifiStr.note_mainplayerfall,this.OnGameOver);
    }

    
    public txtBtnClick(event, customEventData): void {
        
        // 這里 event 是一個 Event 對象,你可以通過 event.target 取到事件的發送節點
        var node = event.target;
        var button: cc.Button = node.getComponent(cc.Button);
        //// 這里的 customEventData 參數就等於你之前設置的 "foobar"
        ////alert("btn:" + customEventData);
        ////button.node.destroy();
        //button.node.y += 50;
        this.CreateNewPlayerToSence();
        this.txtBtn.node.active = false;
    }
    public OnGameOver(param: EventParam): void {
        this.Btn_Reset.active = true;//以這種方式注冊的訂閱者在這里Btn_Reset 始終為undifine,就是根本就未定義。就連此時打印numid都是undefine證明觀察者管理器調用的OnGameOver函數並非注冊時該函數所在的對象。這里猜測着是js的機制,因為之前綁定按鈕事件居然要指定函數所在的腳步名稱、節點、以及函數名稱。
    }
}

這里測試了很多總方法,如果是直接

ui_page_battle.Instance.OnGameOver();的話就一切正常,再次證明了上圖委托調用的猜想。這里將代碼修改為在匿名函數里調用居然正常了。
export default class ui_page_battle extends UIBaseWindow {
    public numid: string = "-1";
    public _AwakeImpl() {
        this.numid = GUtil.GetUUID();
        this.InitUIObject();
        GUtil.BindOnClick(this.txtBtn, this.node, "txtBtnClick", "222");
        XObserverCore.RegisterNotification(ConstDefineNotifiStr.note_mainplayerfall, (o) => {
            this.OnGameOver(o);//改成這樣就正常了
        });
        this.txtBtn.node.active = false;
    }

    public KeyDebug(o: EventParam): void {

        //alert("999999999999999999999999:" + this.numid);
    }
    public _StartOpenImpl() {

        //alert("5555555555:");
        //this.Btn_Reset.active = false;
    }
    public _UpdateImpl(dt) {
        //alert("333333333333333333333333333333:" + this.node.name + " " + this.Btn_Reset.name + " " + this.numid);
    }
    public _DestroyImpl() {
    }
    public txtBtnClick(event, customEventData): void {
        
        // 這里 event 是一個 Event 對象,你可以通過 event.target 取到事件的發送節點
        var node = event.target;
        var button: cc.Button = node.getComponent(cc.Button);
        //// 這里的 customEventData 參數就等於你之前設置的 "foobar"
        ////alert("btn:" + customEventData);
        ////button.node.destroy();
        //button.node.y += 50;
        this.CreateNewPlayerToSence();
        this.txtBtn.node.active = false;
    }
    public OnGameOver(param: EventParam): void {
        this.Btn_Reset.active = true;
    }
}

這里這個得特別注意。

附錄:上面服的調用方法也可用下面這樣調用:

start() {
        let self = this;//用self的方式調用就可避免undifine的問題
        cc.loader.downloader.loadSubpackage('subpackages', function (err) {
            if (err) {
                return console.error(err);
            }
            self.LoadInit();
        });
        
    }
    private LoadInit() {

            this.gameCore = new GameCore();
            this.gameCore.Register();
    }

 

3.操作符遠近的問題================================

var ui: UIBaseWindow = this.GetGameIngWindow(pageName);UI不為空

        if (ui != null) {//為真

            alert("2222222222222");
            this.RemoveWindow(ui);
            ui.CloseWindow(() => {
                if (backcall != null) {
                    backcall();
                }
            });
        }
if (ui! = null) {!號和=號中建有了空格,此時條件為假

            alert("2222222222222");
            this.RemoveWindow(ui);
            ui.CloseWindow(() => {
                if (backcall != null) {
                    backcall();
                }
            });
        }

4.設置局部坐標和世界坐標

item.setPosition(pos);

當item是世界根物體時 設置的坐標就是世界坐標,如果是子物體,就是設置它的局部坐標。

這里要特別注意多個子物體嵌套時,比如A。B。C。A是世界,B是A的自物體同時是C的父物體。且B如果局部坐標不為(0,0),這時如果將C的局部坐標轉換為世界坐標是無法正確的。必須一級一級向上層層轉換。

 

5.委托回調時調用this里的屬性是undefined的問題。

如:

public useWeaponCtrl: UseWeaponControl;
private start(){
let self = this;
        item.RegisterCollisionCall(self.OnCollisioned);
}
private OnCollisioned(layer: string, otherCollider: cc.Node) {
        var other = <cc.Node>otherCollider;
        switch (layer) {
            case "monster":
                var otherCtrl: IPlayerControl = other.getComponent(IPlayerControl);
                console.log("7777777777777777:", this.strkey);
                console.log("6666666666666:", layer, " ", this.useWeaponCtrl.node.getComponent(IPlayerControl));
                otherCtrl.player.useFight.AcceptAtk(this.useWeaponCtrl.node.getComponent(IPlayerControl));
                XAudio.Play("data/audio/audio_hurt", 1, false);
                break;
        }
    }

如果是以item.RegisterCollisionCall(self.OnCollisioned);這種方式回調,受限於js的底層架構問題,回調后再OnCollisioned()函數里這個對象是未定義的。比如

this.useWeaponCtrl就是undefined

解決方法是在注冊委托時直接構建一個匿名函數,然后在匿名函數里調用本對象里的方法,就像下面這樣。

 

public useWeaponCtrl: UseWeaponControl;
private start(){
let self = this;
        item.RegisterCollisionCall((layer: string, other: cc.Node) => {
            self.OnCollisioned(layer, other);
        });
}
private OnCollisioned(layer: string, otherCollider: cc.Node) {
        var other = <cc.Node>otherCollider;
        switch (layer) {
            case "monster":
                var otherCtrl: IPlayerControl = other.getComponent(IPlayerControl);
                console.log("7777777777777777:", this.strkey);
                console.log("6666666666666:", layer, " ", this.useWeaponCtrl.node.getComponent(IPlayerControl));
                otherCtrl.player.useFight.AcceptAtk(this.useWeaponCtrl.node.getComponent(IPlayerControl));
                XAudio.Play("data/audio/audio_hurt", 1, false);
                break;
        }
    }

這樣調用就完全正確。

 

4.集合第二次判斷為空的問題。

private RefreshWeaponList(): void {
        this.playerslist.Clear();
        this.playerslist = XTask.GetAllTaskList();
        console.log("7777777777777777777777777:"+this.playerslist.Count.toString());
    }

  這里this.playerslist.Clear();第一次執行沒問題。但第二次執行時,由於playerlist已經等於了XTask.GetAllTaskList();且由於這里的playerlist是引用類型。所以第二次Clear會直接Clear掉

XTask.GetAllTaskList();這里可以去掉Clear。所以在第二行不要直接使用等於,使用AddRange就可以用Clear了。

----------


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM